2 Contains code that implements the virtual machine.
4 Copyright (c) 2006 - 2008, Intel Corporation
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.
75 Decode a 32-bit index to determine the offset.
77 @param VmPtr A pointer to VM context.
78 @param CodeOffset Offset from IP of the location of the 32-bit index
81 @return Converted index per EBC VM specification.
92 Decode a 64-bit index to determine the offset.
94 @param VmPtr A pointer to VM context.s
95 @param CodeOffset Offset from IP of the location of the 64-bit index
98 @return Converted index per EBC VM specification
104 IN VM_CONTEXT
*VmPtr
,
109 Reads 8-bit data form the memory address.
111 @param VmPtr A pointer to VM context.
112 @param Addr The memory address.
114 @return The 8-bit value from the memory adress.
120 IN VM_CONTEXT
*VmPtr
,
125 Reads 16-bit data form the memory address.
127 @param VmPtr A pointer to VM context.
128 @param Addr The memory address.
130 @return The 16-bit value from the memory adress.
136 IN VM_CONTEXT
*VmPtr
,
141 Reads 32-bit data form the memory address.
143 @param VmPtr A pointer to VM context.
144 @param Addr The memory address.
146 @return The 32-bit value from the memory adress.
152 IN VM_CONTEXT
*VmPtr
,
157 Reads 64-bit data form the memory address.
159 @param VmPtr A pointer to VM context.
160 @param Addr The memory address.
162 @return The 64-bit value from the memory adress.
168 IN VM_CONTEXT
*VmPtr
,
173 Read a natural value from memory. May or may not be aligned.
175 @param VmPtr current VM context
176 @param Addr the address to read from
178 @return The natural value at address Addr.
184 IN VM_CONTEXT
*VmPtr
,
189 Writes 8-bit data to memory address.
191 This routine is called by the EBC data
192 movement instructions that write to memory. Since these writes
193 may be to the stack, which looks like (high address on top) this,
195 [EBC entry point arguments]
199 we need to detect all attempts to write to the EBC entry point argument
200 stack area and adjust the address (which will initially point into the
201 VM stack) to point into the EBC entry point arguments.
203 @param VmPtr A pointer to a VM context.
204 @param Addr Adddress to write to.
205 @param Data Value to write to Addr.
207 @retval EFI_SUCCESS The instruction is executed successfully.
208 @retval Other Some error occurs when writing data to the address.
214 IN VM_CONTEXT
*VmPtr
,
220 Writes 16-bit data to memory address.
222 This routine is called by the EBC data
223 movement instructions that write to memory. Since these writes
224 may be to the stack, which looks like (high address on top) this,
226 [EBC entry point arguments]
230 we need to detect all attempts to write to the EBC entry point argument
231 stack area and adjust the address (which will initially point into the
232 VM stack) to point into the EBC entry point arguments.
234 @param VmPtr A pointer to a VM context.
235 @param Addr Adddress to write to.
236 @param Data Value to write to Addr.
238 @retval EFI_SUCCESS The instruction is executed successfully.
239 @retval Other Some error occurs when writing data to the address.
245 IN VM_CONTEXT
*VmPtr
,
251 Writes 32-bit data to memory address.
253 This routine is called by the EBC data
254 movement instructions that write to memory. Since these writes
255 may be to the stack, which looks like (high address on top) this,
257 [EBC entry point arguments]
261 we need to detect all attempts to write to the EBC entry point argument
262 stack area and adjust the address (which will initially point into the
263 VM stack) to point into the EBC entry point arguments.
265 @param VmPtr A pointer to a VM context.
266 @param Addr Adddress to write to.
267 @param Data Value to write to Addr.
269 @retval EFI_SUCCESS The instruction is executed successfully.
270 @retval Other Some error occurs when writing data to the address.
276 IN VM_CONTEXT
*VmPtr
,
282 Reads 16-bit unsinged data from the code stream.
284 This routine provides the ability to read raw unsigned data from the code
287 @param VmPtr A pointer to VM context
288 @param Offset Offset from current IP to the raw data to read.
290 @return The raw unsigned 16-bit value from the code stream.
296 IN VM_CONTEXT
*VmPtr
,
301 Reads 32-bit unsinged data from the code stream.
303 This routine provides the ability to read raw unsigned data from the code
306 @param VmPtr A pointer to VM context
307 @param Offset Offset from current IP to the raw data to read.
309 @return The raw unsigned 32-bit value from the code stream.
315 IN VM_CONTEXT
*VmPtr
,
320 Reads 64-bit unsinged data from the code stream.
322 This routine provides the ability to read raw unsigned data from the code
325 @param VmPtr A pointer to VM context
326 @param Offset Offset from current IP to the raw data to read.
328 @return The raw unsigned 64-bit value from the code stream.
334 IN VM_CONTEXT
*VmPtr
,
339 Reads 8-bit immediate value at the offset.
341 This routine is called by the EBC execute
342 functions to read EBC immediate values from the code stream.
343 Since we can't assume alignment, each tries to read in the biggest
344 chunks size available, but will revert to smaller reads if necessary.
346 @param VmPtr A pointer to a VM context.
347 @param Offset offset from IP of the code bytes to read.
349 @return Signed data of the requested size from the specified address.
355 IN VM_CONTEXT
*VmPtr
,
360 Reads 16-bit immediate value at the offset.
362 This routine is called by the EBC execute
363 functions to read EBC immediate values from the code stream.
364 Since we can't assume alignment, each tries to read in the biggest
365 chunks size available, but will revert to smaller reads if necessary.
367 @param VmPtr A pointer to a VM context.
368 @param Offset offset from IP of the code bytes to read.
370 @return Signed data of the requested size from the specified address.
376 IN VM_CONTEXT
*VmPtr
,
381 Reads 32-bit immediate value at the offset.
383 This routine is called by the EBC execute
384 functions to read EBC immediate values from the code stream.
385 Since we can't assume alignment, each tries to read in the biggest
386 chunks size available, but will revert to smaller reads if necessary.
388 @param VmPtr A pointer to a VM context.
389 @param Offset offset from IP of the code bytes to read.
391 @return Signed data of the requested size from the specified address.
397 IN VM_CONTEXT
*VmPtr
,
402 Reads 64-bit immediate value at the offset.
404 This routine is called by the EBC execute
405 functions to read EBC immediate values from the code stream.
406 Since we can't assume alignment, each tries to read in the biggest
407 chunks size available, but will revert to smaller reads if necessary.
409 @param VmPtr A pointer to a VM context.
410 @param Offset offset from IP of the code bytes to read.
412 @return Signed data of the requested size from the specified address.
418 IN VM_CONTEXT
*VmPtr
,
423 Given an address that EBC is going to read from or write to, return
424 an appropriate address that accounts for a gap in the stack.
425 The stack for this application looks like this (high addr on top)
426 [EBC entry point arguments]
429 The EBC assumes that its arguments are at the top of its stack, which
430 is where the VM stack is really. Therefore if the EBC does memory
431 accesses into the VM stack area, then we need to convert the address
432 to point to the EBC entry point arguments area. Do this here.
434 @param VmPtr A Pointer to VM context.
435 @param Addr Address of interest
437 @return The unchanged address if it's not in the VM stack region. Otherwise,
438 adjust for the stack gap and return the modified address.
444 IN VM_CONTEXT
*VmPtr
,
449 Execute all the EBC data manipulation instructions.
450 Since the EBC data manipulation instructions all have the same basic form,
451 they can share the code that does the fetch of operands and the write-back
452 of the result. This function performs the fetch of the operands (even if
453 both are not needed to be fetched, like NOT instruction), dispatches to the
454 appropriate subfunction, then writes back the returned result.
457 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
459 @param VmPtr A pointer to VM context.
460 @param IsSignedOp Indicates whether the operand is signed or not.
462 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
463 @retval EFI_SUCCESS The instruction is executed successfully.
469 IN VM_CONTEXT
*VmPtr
,
470 IN BOOLEAN IsSignedOp
474 // Functions that execute VM opcodes
477 Execute the EBC BREAK instruction.
479 @param VmPtr A pointer to a VM context.
481 @retval EFI_SUCCESS The instruction is executed successfully.
491 Execute the JMP instruction.
495 JMP32{cs|cc} {@}R1 {Immed32|Index32}
498 b0.7 - immediate data present
499 b0.6 - 1 = 64 bit immediate data
500 0 = 32 bit immediate data
501 b1.7 - 1 = conditional
502 b1.6 1 = CS (condition set)
503 0 = CC (condition clear)
504 b1.4 1 = relative address
506 b1.3 1 = operand1 indirect
509 @param VmPtr A pointer to a VM context.
511 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
512 @retval EFI_SUCCESS The instruction is executed successfully.
522 Execute the EBC JMP8 instruction.
527 @param VmPtr A pointer to a VM context.
529 @retval EFI_SUCCESS The instruction is executed successfully.
539 Implements the EBC CALL instruction.
543 CALL32 {@}R1 {Immed32|Index32}
545 CALLEX16 {@}R1 {Immed32}
547 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
549 @param VmPtr A pointer to a VM context.
551 @retval EFI_SUCCESS The instruction is executed successfully.
561 Execute the EBC RET instruction.
566 @param VmPtr A pointer to a VM context.
568 @retval EFI_SUCCESS The instruction is executed successfully.
578 Execute the EBC CMP instruction.
581 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
583 @param VmPtr A pointer to a VM context.
585 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
586 @retval EFI_SUCCESS The instruction is executed successfully.
596 Execute the EBC CMPI instruction
599 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
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.
614 Execute the MOVxx instructions.
618 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
619 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
621 Copies contents of [R2] -> [R1], zero extending where required.
623 First character indicates the size of the move.
624 Second character indicates the size of the index(s).
626 Invalid to have R1 direct with index.
628 @param VmPtr A pointer to a VM context.
630 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
631 @retval EFI_SUCCESS The instruction is executed successfully.
641 Execute the EBC MOVI.
645 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
647 First variable character specifies the move size
648 Second variable character specifies size of the immediate data
650 Sign-extend the immediate data to the size of the operation, and zero-extend
651 if storing to a register.
653 Operand1 direct with index/immed is invalid.
655 @param VmPtr A pointer to a VM context.
657 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
658 @retval EFI_SUCCESS The instruction is executed successfully.
668 Execute the EBC MOV immediate natural. This instruction moves an immediate
669 index value into a register or memory location.
673 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
675 @param VmPtr A pointer to a VM context.
677 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
678 @retval EFI_SUCCESS The instruction is executed successfully.
688 Execute the EBC MOVREL instruction.
693 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
695 @param VmPtr A pointer to a VM context.
697 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
698 @retval EFI_SUCCESS The instruction is executed successfully.
708 Execute the EBC PUSHn instruction
711 PUSHn {@}R1 {Index16|Immed16}
713 @param VmPtr A pointer to a VM context.
715 @retval EFI_SUCCESS The instruction is executed successfully.
725 Execute the EBC PUSH instruction.
728 PUSH[32|64] {@}R1 {Index16|Immed16}
730 @param VmPtr A pointer to a VM context.
732 @retval EFI_SUCCESS The instruction is executed successfully.
742 Execute the EBC POPn instruction.
745 POPn {@}R1 {Index16|Immed16}
747 @param VmPtr A pointer to a VM context.
749 @retval EFI_SUCCESS The instruction is executed successfully.
759 Execute the EBC POP instruction.
762 POPn {@}R1 {Index16|Immed16}
764 @param VmPtr A pointer to a VM context.
766 @retval EFI_SUCCESS The instruction is executed successfully.
776 Execute all the EBC signed data manipulation instructions.
777 Since the EBC data manipulation instructions all have the same basic form,
778 they can share the code that does the fetch of operands and the write-back
779 of the result. This function performs the fetch of the operands (even if
780 both are not needed to be fetched, like NOT instruction), dispatches to the
781 appropriate subfunction, then writes back the returned result.
784 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
786 @param VmPtr A pointer to VM context.
788 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
789 @retval EFI_SUCCESS The instruction is executed successfully.
794 ExecuteSignedDataManip (
799 Execute all the EBC unsigned data manipulation instructions.
800 Since the EBC data manipulation instructions all have the same basic form,
801 they can share the code that does the fetch of operands and the write-back
802 of the result. This function performs the fetch of the operands (even if
803 both are not needed to be fetched, like NOT instruction), dispatches to the
804 appropriate subfunction, then writes back the returned result.
807 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
809 @param VmPtr A pointer to VM context.
811 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
812 @retval EFI_SUCCESS The instruction is executed successfully.
817 ExecuteUnsignedDataManip (
822 Execute the EBC LOADSP instruction.
827 @param VmPtr A pointer to a VM context.
829 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
830 @retval EFI_SUCCESS The instruction is executed successfully.
840 Execute the EBC STORESP instruction.
845 @param VmPtr A pointer to a VM context.
847 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
848 @retval EFI_SUCCESS The instruction is executed successfully.
858 Execute the EBC MOVsnw instruction. This instruction loads a signed
859 natural value from memory or register to another memory or register. On
860 32-bit machines, the value gets sign-extended to 64 bits if the destination
865 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
867 0:7 1=>operand1 index present
868 0:6 1=>operand2 index present
870 @param VmPtr A pointer to a VM context.
872 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
873 @retval EFI_SUCCESS The instruction is executed successfully.
883 Execute the EBC MOVsnw instruction. This instruction loads a signed
884 natural value from memory or register to another memory or register. On
885 32-bit machines, the value gets sign-extended to 64 bits if the destination
890 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
892 0:7 1=>operand1 index present
893 0:6 1=>operand2 index present
895 @param VmPtr A pointer to a VM context.
897 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
898 @retval EFI_SUCCESS The instruction is executed successfully.
908 // Data manipulation subfunctions
911 Execute the EBC NOT instruction.s
914 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
916 @param VmPtr A pointer to a VM context.
917 @param Op1 Operand 1 from the instruction
918 @param Op2 Operand 2 from the instruction
926 IN VM_CONTEXT
*VmPtr
,
932 Execute the EBC NEG instruction.
935 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
937 @param VmPtr A pointer to a VM context.
938 @param Op1 Operand 1 from the instruction
939 @param Op2 Operand 2 from the instruction
947 IN VM_CONTEXT
*VmPtr
,
953 Execute the EBC ADD instruction.
956 ADD[32|64] {@}R1, {@}R2 {Index16}
958 @param VmPtr A pointer to a VM context.
959 @param Op1 Operand 1 from the instruction
960 @param Op2 Operand 2 from the instruction
968 IN VM_CONTEXT
*VmPtr
,
974 Execute the EBC SUB instruction.
977 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
979 @param VmPtr A pointer to a VM context.
980 @param Op1 Operand 1 from the instruction
981 @param Op2 Operand 2 from the instruction
989 IN VM_CONTEXT
*VmPtr
,
995 Execute the EBC MUL instruction.
998 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1000 @param VmPtr A pointer to a VM context.
1001 @param Op1 Operand 1 from the instruction
1002 @param Op2 Operand 2 from the instruction
1010 IN VM_CONTEXT
*VmPtr
,
1016 Execute the EBC MULU instruction
1019 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1021 @param VmPtr A pointer to a VM context.
1022 @param Op1 Operand 1 from the instruction
1023 @param Op2 Operand 2 from the instruction
1025 @return (unsigned)Op1 * (unsigned)Op2
1031 IN VM_CONTEXT
*VmPtr
,
1037 Execute the EBC DIV instruction.
1040 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
1042 @param VmPtr A pointer to a VM context.
1043 @param Op1 Operand 1 from the instruction
1044 @param Op2 Operand 2 from the instruction
1052 IN VM_CONTEXT
*VmPtr
,
1058 Execute the EBC DIVU instruction
1061 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1063 @param VmPtr A pointer to a VM context.
1064 @param Op1 Operand 1 from the instruction
1065 @param Op2 Operand 2 from the instruction
1067 @return (unsigned)Op1 / (unsigned)Op2
1073 IN VM_CONTEXT
*VmPtr
,
1079 Execute the EBC MOD instruction.
1082 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1084 @param VmPtr A pointer to a VM context.
1085 @param Op1 Operand 1 from the instruction
1086 @param Op2 Operand 2 from the instruction
1088 @return Op1 MODULUS Op2
1094 IN VM_CONTEXT
*VmPtr
,
1100 Execute the EBC MODU instruction.
1103 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1105 @param VmPtr A pointer to a VM context.
1106 @param Op1 Operand 1 from the instruction
1107 @param Op2 Operand 2 from the instruction
1109 @return Op1 UNSIGNED_MODULUS Op2
1115 IN VM_CONTEXT
*VmPtr
,
1121 Execute the EBC AND instruction.
1124 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1126 @param VmPtr A pointer to a VM context.
1127 @param Op1 Operand 1 from the instruction
1128 @param Op2 Operand 2 from the instruction
1136 IN VM_CONTEXT
*VmPtr
,
1142 Execute the EBC OR instruction.
1145 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1147 @param VmPtr A pointer to a VM context.
1148 @param Op1 Operand 1 from the instruction
1149 @param Op2 Operand 2 from the instruction
1157 IN VM_CONTEXT
*VmPtr
,
1163 Execute the EBC XOR instruction.
1166 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1168 @param VmPtr A pointer to a VM context.
1169 @param Op1 Operand 1 from the instruction
1170 @param Op2 Operand 2 from the instruction
1178 IN VM_CONTEXT
*VmPtr
,
1184 Execute the EBC SHL shift left instruction.
1187 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1189 @param VmPtr A pointer to a VM context.
1190 @param Op1 Operand 1 from the instruction
1191 @param Op2 Operand 2 from the instruction
1199 IN VM_CONTEXT
*VmPtr
,
1205 Execute the EBC SHR instruction.
1208 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1210 @param VmPtr A pointer to a VM context.
1211 @param Op1 Operand 1 from the instruction
1212 @param Op2 Operand 2 from the instruction
1214 @return Op1 >> Op2 (unsigned operands)
1220 IN VM_CONTEXT
*VmPtr
,
1226 Execute the EBC ASHR instruction.
1229 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1231 @param VmPtr A pointer to a VM context.
1232 @param Op1 Operand 1 from the instruction
1233 @param Op2 Operand 2 from the instruction
1235 @return Op1 >> Op2 (signed)
1241 IN VM_CONTEXT
*VmPtr
,
1247 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1250 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1252 @param VmPtr A pointer to a VM context.
1253 @param Op1 Operand 1 from the instruction
1254 @param Op2 Operand 2 from the instruction
1256 @return (INT64)(INT8)Op2
1262 IN VM_CONTEXT
*VmPtr
,
1268 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1271 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1273 @param VmPtr A pointer to a VM context.
1274 @param Op1 Operand 1 from the instruction
1275 @param Op2 Operand 2 from the instruction
1277 @return (INT64)(INT16)Op2
1283 IN VM_CONTEXT
*VmPtr
,
1289 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1292 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1294 @param VmPtr A pointer to a VM context.
1295 @param Op1 Operand 1 from the instruction
1296 @param Op2 Operand 2 from the instruction
1298 @return (INT64)(INT32)Op2
1304 IN VM_CONTEXT
*VmPtr
,
1310 // Once we retrieve the operands for the data manipulation instructions,
1311 // call these functions to perform the operation.
1313 STATIC CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1335 STATIC CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1336 { ExecuteBREAK
}, // opcode 0x00
1337 { ExecuteJMP
}, // opcode 0x01
1338 { ExecuteJMP8
}, // opcode 0x02
1339 { ExecuteCALL
}, // opcode 0x03
1340 { ExecuteRET
}, // opcode 0x04
1341 { ExecuteCMP
}, // opcode 0x05 CMPeq
1342 { ExecuteCMP
}, // opcode 0x06 CMPlte
1343 { ExecuteCMP
}, // opcode 0x07 CMPgte
1344 { ExecuteCMP
}, // opcode 0x08 CMPulte
1345 { ExecuteCMP
}, // opcode 0x09 CMPugte
1346 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1347 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1348 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1349 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1350 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1351 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1352 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1353 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1354 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1355 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1356 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1357 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1358 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1359 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1360 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1361 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1362 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1363 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1364 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1365 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1366 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1367 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1368 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1369 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1370 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1371 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1372 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1373 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1374 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1375 { NULL
}, // opcode 0x27
1376 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1377 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1378 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1379 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1380 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1381 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1382 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1383 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1384 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1385 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1386 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1387 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1388 { NULL
}, // opcode 0x34
1389 { ExecutePUSHn
}, // opcode 0x35
1390 { ExecutePOPn
}, // opcode 0x36
1391 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1392 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1393 { ExecuteMOVREL
} // opcode 0x39 - move data relative to PC
1397 // Length of JMP instructions, depending on upper two bits of opcode.
1399 STATIC CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1402 // Simple Debugger Protocol GUID
1404 EFI_GUID mEbcSimpleDebuggerProtocolGuid
= EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID
;
1408 Given a pointer to a new VM context, execute one or more instructions. This
1409 function is only used for test purposes via the EBC VM test protocol.
1411 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1412 @param VmPtr A pointer to a VM context.
1413 @param InstructionCount A pointer to a UINTN value holding the number of
1414 instructions to execute. If it holds value of 0,
1415 then the instruction to be executed is 1.
1417 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1418 @retval EFI_SUCCESS All of the instructions are executed successfully.
1422 EbcExecuteInstructions (
1423 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1424 IN VM_CONTEXT
*VmPtr
,
1425 IN OUT UINTN
*InstructionCount
1430 UINTN InstructionsLeft
;
1431 UINTN SavedInstructionCount
;
1433 Status
= EFI_SUCCESS
;
1435 if (*InstructionCount
== 0) {
1436 InstructionsLeft
= 1;
1438 InstructionsLeft
= *InstructionCount
;
1441 SavedInstructionCount
= *InstructionCount
;
1442 *InstructionCount
= 0;
1445 // Index into the opcode table using the opcode byte for this instruction.
1446 // This gives you the execute function, which we first test for null, then
1447 // call it if it's not null.
1449 while (InstructionsLeft
!= 0) {
1450 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction
;
1451 if (ExecFunc
== (UINTN
) NULL
) {
1452 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1453 return EFI_UNSUPPORTED
;
1455 mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction (VmPtr
);
1456 *InstructionCount
= *InstructionCount
+ 1;
1460 // Decrement counter if applicable
1462 if (SavedInstructionCount
!= 0) {
1472 Execute an EBC image from an entry point or from a published protocol.
1474 @param VmPtr A pointer to a VM context.
1476 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1477 @retval EFI_SUCCESS All of the instructions are executed successfully.
1482 IN VM_CONTEXT
*VmPtr
1486 UINT8 StackCorrupted
;
1488 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1491 EbcSimpleDebugger
= NULL
;
1492 Status
= EFI_SUCCESS
;
1496 // Make sure the magic value has been put on the stack before we got here.
1498 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1502 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->R
[0] + 8);
1505 // Try to get the debug support for EBC
1507 DEBUG_CODE_BEGIN ();
1508 Status
= gBS
->LocateProtocol (
1509 &mEbcSimpleDebuggerProtocolGuid
,
1511 (VOID
**) &EbcSimpleDebugger
1513 if (EFI_ERROR (Status
)) {
1514 EbcSimpleDebugger
= NULL
;
1519 // Save the start IP for debug. For example, if we take an exception we
1520 // can print out the location of the exception relative to the entry point,
1521 // which could then be used in a disassembly listing to find the problem.
1523 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1526 // We'll wait for this flag to know when we're done. The RET
1527 // instruction sets it if it runs out of stack.
1529 VmPtr
->StopFlags
= 0;
1530 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1532 // If we've found a simple debugger protocol, call it
1534 DEBUG_CODE_BEGIN ();
1535 if (EbcSimpleDebugger
!= NULL
) {
1536 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1541 // Verify the opcode is in range. Otherwise generate an exception.
1543 if ((*VmPtr
->Ip
& OPCODE_M_OPCODE
) >= (sizeof (mVmOpcodeTable
) / sizeof (mVmOpcodeTable
[0]))) {
1544 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1545 Status
= EFI_UNSUPPORTED
;
1549 // Use the opcode bits to index into the opcode dispatch table. If the
1550 // function pointer is null then generate an exception.
1552 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1553 if (ExecFunc
== (UINTN
) NULL
) {
1554 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1555 Status
= EFI_UNSUPPORTED
;
1559 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1560 // and after each instruction is executed.
1564 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1569 // If the step flag is set, signal an exception and continue. We don't
1570 // clear it here. Assuming the debugger is responsible for clearing it.
1572 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1573 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1576 // Make sure stack has not been corrupted. Only report it once though.
1578 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1579 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1582 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->R
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1583 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1596 Execute the MOVxx instructions.
1600 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1601 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1603 Copies contents of [R2] -> [R1], zero extending where required.
1605 First character indicates the size of the move.
1606 Second character indicates the size of the index(s).
1608 Invalid to have R1 direct with index.
1610 @param VmPtr A pointer to a VM context.
1612 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1613 @retval EFI_SUCCESS The instruction is executed successfully.
1619 IN VM_CONTEXT
*VmPtr
1635 Opcode
= GETOPCODE (VmPtr
);
1636 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1639 // Get the operands byte so we can get R1 and R2
1641 Operands
= GETOPERANDS (VmPtr
);
1644 // Assume no indexes
1651 // Determine if we have an index/immediate data. Base instruction size
1652 // is 2 (opcode + operands). Add to this size each index specified.
1655 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1657 // Determine size of the index from the opcode. Then get it.
1659 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1661 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1662 // Get one or both index values.
1664 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1665 Index16
= VmReadIndex16 (VmPtr
, 2);
1666 Index64Op1
= (INT64
) Index16
;
1667 Size
+= sizeof (UINT16
);
1670 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1671 Index16
= VmReadIndex16 (VmPtr
, Size
);
1672 Index64Op2
= (INT64
) Index16
;
1673 Size
+= sizeof (UINT16
);
1675 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1677 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1679 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1680 Index32
= VmReadIndex32 (VmPtr
, 2);
1681 Index64Op1
= (INT64
) Index32
;
1682 Size
+= sizeof (UINT32
);
1685 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1686 Index32
= VmReadIndex32 (VmPtr
, Size
);
1687 Index64Op2
= (INT64
) Index32
;
1688 Size
+= sizeof (UINT32
);
1690 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1692 // MOVqq -- only form with a 64-bit index
1694 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1695 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1696 Size
+= sizeof (UINT64
);
1699 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1700 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1701 Size
+= sizeof (UINT64
);
1705 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1707 EbcDebugSignalException (
1708 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1709 EXCEPTION_FLAG_FATAL
,
1712 return EFI_UNSUPPORTED
;
1716 // Determine the size of the move, and create a mask for it so we can
1717 // clear unused bits.
1719 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1720 MoveSize
= DATA_SIZE_8
;
1722 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1723 MoveSize
= DATA_SIZE_16
;
1725 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1726 MoveSize
= DATA_SIZE_32
;
1727 DataMask
= 0xFFFFFFFF;
1728 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1729 MoveSize
= DATA_SIZE_64
;
1730 DataMask
= (UINT64
)~0;
1731 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1732 MoveSize
= DATA_SIZE_N
;
1733 DataMask
= (UINT64
)~0 >> (64 - 8 * sizeof (UINTN
));
1736 // We were dispatched to this function and we don't recognize the opcode
1738 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1739 return EFI_UNSUPPORTED
;
1742 // Now get the source address
1744 if (OPERAND2_INDIRECT (Operands
)) {
1746 // Indirect form @R2. Compute address of operand2
1748 Source
= (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1750 // Now get the data from the source. Always 0-extend and let the compiler
1751 // sign-extend where required.
1755 Data64
= (UINT64
) (UINT8
) VmReadMem8 (VmPtr
, Source
);
1759 Data64
= (UINT64
) (UINT16
) VmReadMem16 (VmPtr
, Source
);
1763 Data64
= (UINT64
) (UINT32
) VmReadMem32 (VmPtr
, Source
);
1767 Data64
= (UINT64
) VmReadMem64 (VmPtr
, Source
);
1771 Data64
= (UINT64
) (UINTN
) VmReadMemN (VmPtr
, Source
);
1782 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1784 Data64
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
;
1786 // Did Operand2 have an index? If so, treat as two signed values since
1787 // indexes are signed values.
1789 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1791 // NOTE: need to find a way to fix this, most likely by changing the VM
1792 // implementation to remove the stack gap. To do that, we'd need to
1793 // allocate stack space for the VM and actually set the system
1794 // stack pointer to the allocated buffer when the VM starts.
1796 // Special case -- if someone took the address of a function parameter
1797 // then we need to make sure it's not in the stack gap. We can identify
1798 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1799 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1800 // Situations that to be aware of:
1801 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1803 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1804 (!OPERAND2_INDIRECT (Operands
)) &&
1806 (OPERAND1_REGNUM (Operands
) == 0) &&
1807 (OPERAND1_INDIRECT (Operands
))
1809 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1814 // Now write it back
1816 if (OPERAND1_INDIRECT (Operands
)) {
1818 // Reuse the Source variable to now be dest.
1820 Source
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1822 // Do the write based on the size
1826 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1830 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1834 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1838 VmWriteMem64 (VmPtr
, Source
, Data64
);
1842 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1854 // Make sure we didn't have an index on operand1.
1856 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1857 EbcDebugSignalException (
1858 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1859 EXCEPTION_FLAG_FATAL
,
1862 return EFI_UNSUPPORTED
;
1865 // Direct storage in register. Clear unused bits and store back to
1868 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1871 // Advance the instruction pointer
1879 Execute the EBC BREAK instruction.
1881 @param VmPtr A pointer to a VM context.
1883 @retval EFI_SUCCESS The instruction is executed successfully.
1889 IN VM_CONTEXT
*VmPtr
1893 VOID
*EbcEntryPoint
;
1895 UINT64 U64EbcEntryPoint
;
1898 Operands
= GETOPERANDS (VmPtr
);
1901 // Runaway program break. Generate an exception and terminate
1904 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1908 // Get VM version -- return VM revision number in R7
1914 // 16-8 = Major version
1915 // 7-0 = Minor version
1917 VmPtr
->R
[7] = GetVmVersion ();
1921 // Debugger breakpoint
1924 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1926 // See if someone has registered a handler
1928 EbcDebugSignalException (
1929 EXCEPT_EBC_BREAKPOINT
,
1930 EXCEPTION_FLAG_NONE
,
1936 // System call, which there are none, so NOP it.
1942 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1943 // "offset from self" pointer to the EBC entry point.
1944 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1947 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[7]);
1948 U64EbcEntryPoint
= (UINT64
) (VmPtr
->R
[7] + Offset
+ 4);
1949 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1952 // Now create a new thunk
1954 EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1957 // Finally replace the EBC entry point memory with the thunk address
1959 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[7], (UINT64
) (UINTN
) Thunk
);
1963 // Compiler setting version per value in R7
1966 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->R
[7];
1968 // Check compiler version against VM version?
1973 // Unhandled break code. Signal exception.
1976 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1988 Execute the JMP instruction.
1991 JMP64{cs|cc} Immed64
1992 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1995 b0.7 - immediate data present
1996 b0.6 - 1 = 64 bit immediate data
1997 0 = 32 bit immediate data
1998 b1.7 - 1 = conditional
1999 b1.6 1 = CS (condition set)
2000 0 = CC (condition clear)
2001 b1.4 1 = relative address
2002 0 = absolute address
2003 b1.3 1 = operand1 indirect
2006 @param VmPtr A pointer to a VM context.
2008 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2009 @retval EFI_SUCCESS The instruction is executed successfully.
2015 IN VM_CONTEXT
*VmPtr
2020 UINT8 ConditionFlag
;
2027 Operand
= GETOPERANDS (VmPtr
);
2028 Opcode
= GETOPCODE (VmPtr
);
2031 // Get instruction length from the opcode. The upper two bits are used here
2032 // to index into the length array.
2034 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
2037 // Decode instruction conditions
2038 // If we haven't met the condition, then simply advance the IP and return.
2040 CompareSet
= (UINT8
) (((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
2041 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2042 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
2043 if (CompareSet
!= ConditionFlag
) {
2049 // Check for 64-bit form and do it right away since it's the most
2050 // straight-forward form.
2052 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2054 // Double check for immediate-data, which is required. If not there,
2055 // then signal an exception
2057 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
2058 EbcDebugSignalException (
2059 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2060 EXCEPTION_FLAG_ERROR
,
2063 return EFI_UNSUPPORTED
;
2066 // 64-bit immediate data is full address. Read the immediate data,
2067 // check for alignment, and jump absolute.
2069 Data64
= VmReadImmed64 (VmPtr
, 2);
2070 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2071 EbcDebugSignalException (
2072 EXCEPT_EBC_ALIGNMENT_CHECK
,
2073 EXCEPTION_FLAG_FATAL
,
2077 return EFI_UNSUPPORTED
;
2081 // Take jump -- relative or absolute
2083 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2084 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2086 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2093 // Get the index if there is one. May be either an index, or an immediate
2094 // offset depending on indirect operand.
2095 // JMP32 @R1 Index32 -- immediate data is an index
2096 // JMP32 R1 Immed32 -- immedate data is an offset
2098 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2099 if (OPERAND1_INDIRECT (Operand
)) {
2100 Index32
= VmReadIndex32 (VmPtr
, 2);
2102 Index32
= VmReadImmed32 (VmPtr
, 2);
2108 // Get the register data. If R == 0, then special case where it's ignored.
2110 if (OPERAND1_REGNUM (Operand
) == 0) {
2113 Data64
= OPERAND1_REGDATA (VmPtr
, Operand
);
2118 if (OPERAND1_INDIRECT (Operand
)) {
2120 // Form: JMP32 @Rx {Index32}
2122 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2123 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2124 EbcDebugSignalException (
2125 EXCEPT_EBC_ALIGNMENT_CHECK
,
2126 EXCEPTION_FLAG_FATAL
,
2130 return EFI_UNSUPPORTED
;
2133 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2134 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2136 VmPtr
->Ip
= (VMIP
) Addr
;
2140 // Form: JMP32 Rx {Immed32}
2142 Addr
= (UINTN
) (Data64
+ Index32
);
2143 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2144 EbcDebugSignalException (
2145 EXCEPT_EBC_ALIGNMENT_CHECK
,
2146 EXCEPTION_FLAG_FATAL
,
2150 return EFI_UNSUPPORTED
;
2153 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2154 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2156 VmPtr
->Ip
= (VMIP
) Addr
;
2165 Execute the EBC JMP8 instruction.
2168 JMP8{cs|cc} Offset/2
2170 @param VmPtr A pointer to a VM context.
2172 @retval EFI_SUCCESS The instruction is executed successfully.
2178 IN VM_CONTEXT
*VmPtr
2182 UINT8 ConditionFlag
;
2187 // Decode instruction.
2189 Opcode
= GETOPCODE (VmPtr
);
2190 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2191 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2194 // If we haven't met the condition, then simply advance the IP and return
2196 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2197 if (CompareSet
!= ConditionFlag
) {
2203 // Get the offset from the instruction stream. It's relative to the
2204 // following instruction, and divided by 2.
2206 Offset
= VmReadImmed8 (VmPtr
, 1);
2208 // Want to check for offset == -2 and then raise an exception?
2210 VmPtr
->Ip
+= (Offset
* 2) + 2;
2216 Execute the EBC MOVI.
2220 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2222 First variable character specifies the move size
2223 Second variable character specifies size of the immediate data
2225 Sign-extend the immediate data to the size of the operation, and zero-extend
2226 if storing to a register.
2228 Operand1 direct with index/immed is invalid.
2230 @param VmPtr A pointer to a VM context.
2232 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2233 @retval EFI_SUCCESS The instruction is executed successfully.
2239 IN VM_CONTEXT
*VmPtr
2251 // Get the opcode and operands byte so we can get R1 and R2
2253 Opcode
= GETOPCODE (VmPtr
);
2254 Operands
= GETOPERANDS (VmPtr
);
2257 // Get the index (16-bit) if present
2259 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2260 Index16
= VmReadIndex16 (VmPtr
, 2);
2267 // Extract the immediate data. Sign-extend always.
2269 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2270 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2272 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2273 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2275 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2276 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2282 EbcDebugSignalException (
2283 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2284 EXCEPTION_FLAG_FATAL
,
2287 return EFI_UNSUPPORTED
;
2290 // Now write back the result
2292 if (!OPERAND1_INDIRECT (Operands
)) {
2294 // Operand1 direct. Make sure it didn't have an index.
2296 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2297 EbcDebugSignalException (
2298 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2299 EXCEPTION_FLAG_FATAL
,
2302 return EFI_UNSUPPORTED
;
2305 // Writing directly to a register. Clear unused bits.
2307 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2308 Mask64
= 0x000000FF;
2309 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2310 Mask64
= 0x0000FFFF;
2311 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2312 Mask64
= 0x00000000FFFFFFFF;
2314 Mask64
= (UINT64
)~0;
2317 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2320 // Get the address then write back based on size of the move
2322 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2323 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2324 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2325 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2326 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2327 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2328 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2330 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, ImmData64
);
2334 // Advance the instruction pointer
2342 Execute the EBC MOV immediate natural. This instruction moves an immediate
2343 index value into a register or memory location.
2347 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2349 @param VmPtr A pointer to a VM context.
2351 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2352 @retval EFI_SUCCESS The instruction is executed successfully.
2358 IN VM_CONTEXT
*VmPtr
2371 // Get the opcode and operands byte so we can get R1 and R2
2373 Opcode
= GETOPCODE (VmPtr
);
2374 Operands
= GETOPERANDS (VmPtr
);
2377 // Get the operand1 index (16-bit) if present
2379 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2380 Index16
= VmReadIndex16 (VmPtr
, 2);
2387 // Extract the immediate data and convert to a 64-bit index.
2389 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2390 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2391 ImmedIndex64
= (INT64
) ImmedIndex16
;
2393 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2394 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2395 ImmedIndex64
= (INT64
) ImmedIndex32
;
2397 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2398 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2404 EbcDebugSignalException (
2405 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2406 EXCEPTION_FLAG_FATAL
,
2409 return EFI_UNSUPPORTED
;
2412 // Now write back the result
2414 if (!OPERAND1_INDIRECT (Operands
)) {
2416 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2419 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2420 EbcDebugSignalException (
2421 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2422 EXCEPTION_FLAG_FATAL
,
2425 return EFI_UNSUPPORTED
;
2428 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2433 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2434 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (INTN
) ImmedIndex64
);
2437 // Advance the instruction pointer
2445 Execute the EBC MOVREL instruction.
2446 Dest <- Ip + ImmData
2450 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2452 @param VmPtr A pointer to a VM context.
2454 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2455 @retval EFI_SUCCESS The instruction is executed successfully.
2461 IN VM_CONTEXT
*VmPtr
2473 // Get the opcode and operands byte so we can get R1 and R2
2475 Opcode
= GETOPCODE (VmPtr
);
2476 Operands
= GETOPERANDS (VmPtr
);
2479 // Get the Operand 1 index (16-bit) if present
2481 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2482 Index16
= VmReadIndex16 (VmPtr
, 2);
2489 // Get the immediate data.
2491 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2492 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2494 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2495 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2497 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2498 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2504 EbcDebugSignalException (
2505 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2506 EXCEPTION_FLAG_FATAL
,
2509 return EFI_UNSUPPORTED
;
2512 // Compute the value and write back the result
2514 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2515 if (!OPERAND1_INDIRECT (Operands
)) {
2517 // Check for illegal combination of operand1 direct with immediate data
2519 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2520 EbcDebugSignalException (
2521 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2522 EXCEPTION_FLAG_FATAL
,
2525 return EFI_UNSUPPORTED
;
2528 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2531 // Get the address = [Rx] + Index16
2532 // Write back the result. Always a natural size write, since
2533 // we're talking addresses here.
2535 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2536 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2539 // Advance the instruction pointer
2547 Execute the EBC MOVsnw instruction. This instruction loads a signed
2548 natural value from memory or register to another memory or register. On
2549 32-bit machines, the value gets sign-extended to 64 bits if the destination
2554 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2556 0:7 1=>operand1 index present
2557 0:6 1=>operand2 index present
2559 @param VmPtr A pointer to a VM context.
2561 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2562 @retval EFI_SUCCESS The instruction is executed successfully.
2568 IN VM_CONTEXT
*VmPtr
2579 // Get the opcode and operand bytes
2581 Opcode
= GETOPCODE (VmPtr
);
2582 Operands
= GETOPERANDS (VmPtr
);
2584 Op1Index
= Op2Index
= 0;
2587 // Get the indexes if present.
2590 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2591 if (OPERAND1_INDIRECT (Operands
)) {
2592 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2595 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2597 EbcDebugSignalException (
2598 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2599 EXCEPTION_FLAG_FATAL
,
2602 return EFI_UNSUPPORTED
;
2605 Size
+= sizeof (UINT16
);
2608 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2609 if (OPERAND2_INDIRECT (Operands
)) {
2610 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2612 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2615 Size
+= sizeof (UINT16
);
2618 // Get the data from the source.
2620 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2621 if (OPERAND2_INDIRECT (Operands
)) {
2622 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2625 // Now write back the result.
2627 if (!OPERAND1_INDIRECT (Operands
)) {
2628 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2630 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2633 // Advance the instruction pointer
2641 Execute the EBC MOVsnw instruction. This instruction loads a signed
2642 natural value from memory or register to another memory or register. On
2643 32-bit machines, the value gets sign-extended to 64 bits if the destination
2648 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2650 0:7 1=>operand1 index present
2651 0:6 1=>operand2 index present
2653 @param VmPtr A pointer to a VM context.
2655 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2656 @retval EFI_SUCCESS The instruction is executed successfully.
2662 IN VM_CONTEXT
*VmPtr
2673 // Get the opcode and operand bytes
2675 Opcode
= GETOPCODE (VmPtr
);
2676 Operands
= GETOPERANDS (VmPtr
);
2678 Op1Index
= Op2Index
= 0;
2681 // Get the indexes if present.
2684 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2685 if (OPERAND1_INDIRECT (Operands
)) {
2686 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2689 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2691 EbcDebugSignalException (
2692 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2693 EXCEPTION_FLAG_FATAL
,
2696 return EFI_UNSUPPORTED
;
2699 Size
+= sizeof (UINT32
);
2702 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2703 if (OPERAND2_INDIRECT (Operands
)) {
2704 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2706 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2709 Size
+= sizeof (UINT32
);
2712 // Get the data from the source.
2714 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2715 if (OPERAND2_INDIRECT (Operands
)) {
2716 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2719 // Now write back the result.
2721 if (!OPERAND1_INDIRECT (Operands
)) {
2722 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2724 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2727 // Advance the instruction pointer
2735 Execute the EBC PUSHn instruction
2738 PUSHn {@}R1 {Index16|Immed16}
2740 @param VmPtr A pointer to a VM context.
2742 @retval EFI_SUCCESS The instruction is executed successfully.
2748 IN VM_CONTEXT
*VmPtr
2757 // Get opcode and operands
2759 Opcode
= GETOPCODE (VmPtr
);
2760 Operands
= GETOPERANDS (VmPtr
);
2763 // Get index if present
2765 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2766 if (OPERAND1_INDIRECT (Operands
)) {
2767 Index16
= VmReadIndex16 (VmPtr
, 2);
2769 Index16
= VmReadImmed16 (VmPtr
, 2);
2778 // Get the data to push
2780 if (OPERAND1_INDIRECT (Operands
)) {
2781 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2783 DataN
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
);
2786 // Adjust the stack down.
2788 VmPtr
->R
[0] -= sizeof (UINTN
);
2789 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], DataN
);
2795 Execute the EBC PUSH instruction.
2798 PUSH[32|64] {@}R1 {Index16|Immed16}
2800 @param VmPtr A pointer to a VM context.
2802 @retval EFI_SUCCESS The instruction is executed successfully.
2808 IN VM_CONTEXT
*VmPtr
2818 // Get opcode and operands
2820 Opcode
= GETOPCODE (VmPtr
);
2821 Operands
= GETOPERANDS (VmPtr
);
2823 // Get immediate index if present, then advance the IP.
2825 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2826 if (OPERAND1_INDIRECT (Operands
)) {
2827 Index16
= VmReadIndex16 (VmPtr
, 2);
2829 Index16
= VmReadImmed16 (VmPtr
, 2);
2838 // Get the data to push
2840 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2841 if (OPERAND1_INDIRECT (Operands
)) {
2842 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2844 Data64
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2847 // Adjust the stack down, then write back the data
2849 VmPtr
->R
[0] -= sizeof (UINT64
);
2850 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data64
);
2855 if (OPERAND1_INDIRECT (Operands
)) {
2856 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2858 Data32
= (UINT32
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2861 // Adjust the stack down and write the data
2863 VmPtr
->R
[0] -= sizeof (UINT32
);
2864 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data32
);
2872 Execute the EBC POPn instruction.
2875 POPn {@}R1 {Index16|Immed16}
2877 @param VmPtr A pointer to a VM context.
2879 @retval EFI_SUCCESS The instruction is executed successfully.
2885 IN VM_CONTEXT
*VmPtr
2894 // Get opcode and operands
2896 Opcode
= GETOPCODE (VmPtr
);
2897 Operands
= GETOPERANDS (VmPtr
);
2899 // Get immediate data if present, and advance the IP
2901 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2902 if (OPERAND1_INDIRECT (Operands
)) {
2903 Index16
= VmReadIndex16 (VmPtr
, 2);
2905 Index16
= VmReadImmed16 (VmPtr
, 2);
2914 // Read the data off the stack, then adjust the stack pointer
2916 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2917 VmPtr
->R
[0] += sizeof (UINTN
);
2919 // Do the write-back
2921 if (OPERAND1_INDIRECT (Operands
)) {
2922 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2924 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) ((UINTN
) DataN
+ Index16
);
2932 Execute the EBC POP instruction.
2935 POPn {@}R1 {Index16|Immed16}
2937 @param VmPtr A pointer to a VM context.
2939 @retval EFI_SUCCESS The instruction is executed successfully.
2945 IN VM_CONTEXT
*VmPtr
2955 // Get opcode and operands
2957 Opcode
= GETOPCODE (VmPtr
);
2958 Operands
= GETOPERANDS (VmPtr
);
2960 // Get immediate data if present, and advance the IP.
2962 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2963 if (OPERAND1_INDIRECT (Operands
)) {
2964 Index16
= VmReadIndex16 (VmPtr
, 2);
2966 Index16
= VmReadImmed16 (VmPtr
, 2);
2975 // Get the data off the stack, then write it to the appropriate location
2977 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2979 // Read the data off the stack, then adjust the stack pointer
2981 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2982 VmPtr
->R
[0] += sizeof (UINT64
);
2984 // Do the write-back
2986 if (OPERAND1_INDIRECT (Operands
)) {
2987 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2989 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2993 // 32-bit pop. Read it off the stack and adjust the stack pointer
2995 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2996 VmPtr
->R
[0] += sizeof (UINT32
);
2998 // Do the write-back
3000 if (OPERAND1_INDIRECT (Operands
)) {
3001 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
3003 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
3012 Implements the EBC CALL instruction.
3016 CALL32 {@}R1 {Immed32|Index32}
3018 CALLEX16 {@}R1 {Immed32}
3020 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
3022 @param VmPtr A pointer to a VM context.
3024 @retval EFI_SUCCESS The instruction is executed successfully.
3030 IN VM_CONTEXT
*VmPtr
3041 // Get opcode and operands
3043 Opcode
= GETOPCODE (VmPtr
);
3044 Operands
= GETOPERANDS (VmPtr
);
3046 // Assign these as well to avoid compiler warnings
3051 FramePtr
= VmPtr
->FramePtr
;
3053 // Determine the instruction size, and get immediate data if present
3055 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3056 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3057 Immed64
= VmReadImmed64 (VmPtr
, 2);
3061 // If register operand is indirect, then the immediate data is an index
3063 if (OPERAND1_INDIRECT (Operands
)) {
3064 Immed32
= VmReadIndex32 (VmPtr
, 2);
3066 Immed32
= VmReadImmed32 (VmPtr
, 2);
3075 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3076 // put our return address and frame pointer on the VM stack.
3078 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3080 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINTN
) FramePtr
);
3081 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->R
[0];
3083 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3086 // If 64-bit data, then absolute jump only
3088 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3090 // Native or EBC call?
3092 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3093 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3096 // Call external function, get the return value, and advance the IP
3098 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3102 // Get the register data. If operand1 == 0, then ignore register and
3103 // take immediate data as relative or absolute address.
3104 // Compiler should take care of upper bits if 32-bit machine.
3106 if (OPERAND1_REGNUM (Operands
) != 0) {
3107 Immed64
= (UINT64
) (UINTN
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3110 // Get final address
3112 if (OPERAND1_INDIRECT (Operands
)) {
3113 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3118 // Now determine if external call, and then if relative or absolute
3120 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3122 // EBC call. Relative or absolute? If relative, then it's relative to the
3123 // start of the next instruction.
3125 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3126 VmPtr
->Ip
+= Immed64
+ Size
;
3128 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3132 // Native call. Relative or absolute?
3134 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3135 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3137 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3141 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3151 Execute the EBC RET instruction.
3156 @param VmPtr A pointer to a VM context.
3158 @retval EFI_SUCCESS The instruction is executed successfully.
3164 IN VM_CONTEXT
*VmPtr
3168 // If we're at the top of the stack, then simply set the done
3171 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->R
[0]) {
3172 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3175 // Pull the return address off the VM app's stack and set the IP
3178 if (!IS_ALIGNED ((UINTN
) VmPtr
->R
[0], sizeof (UINT16
))) {
3179 EbcDebugSignalException (
3180 EXCEPT_EBC_ALIGNMENT_CHECK
,
3181 EXCEPTION_FLAG_FATAL
,
3186 // Restore the IP and frame pointer from the stack
3188 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3190 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3199 Execute the EBC CMP instruction.
3202 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3204 @param VmPtr A pointer to a VM context.
3206 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3207 @retval EFI_SUCCESS The instruction is executed successfully.
3213 IN VM_CONTEXT
*VmPtr
3225 // Get opcode and operands
3227 Opcode
= GETOPCODE (VmPtr
);
3228 Operands
= GETOPERANDS (VmPtr
);
3230 // Get the register data we're going to compare to
3232 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3234 // Get immediate data
3236 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3237 if (OPERAND2_INDIRECT (Operands
)) {
3238 Index16
= VmReadIndex16 (VmPtr
, 2);
3240 Index16
= VmReadImmed16 (VmPtr
, 2);
3251 if (OPERAND2_INDIRECT (Operands
)) {
3252 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3253 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
));
3256 // 32-bit operations. 0-extend the values for all cases.
3258 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3261 Op2
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
3264 // Now do the compare
3267 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3271 switch (Opcode
& OPCODE_M_OPCODE
) {
3290 case OPCODE_CMPULTE
:
3291 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3296 case OPCODE_CMPUGTE
:
3297 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3309 switch (Opcode
& OPCODE_M_OPCODE
) {
3311 if ((INT32
) Op1
== (INT32
) Op2
) {
3317 if ((INT32
) Op1
<= (INT32
) Op2
) {
3323 if ((INT32
) Op1
>= (INT32
) Op2
) {
3328 case OPCODE_CMPULTE
:
3329 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3334 case OPCODE_CMPUGTE
:
3335 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3345 // Now set the flag accordingly for the comparison
3348 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3350 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3361 Execute the EBC CMPI instruction
3364 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3366 @param VmPtr A pointer to a VM context.
3368 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3369 @retval EFI_SUCCESS The instruction is executed successfully.
3375 IN VM_CONTEXT
*VmPtr
3387 // Get opcode and operands
3389 Opcode
= GETOPCODE (VmPtr
);
3390 Operands
= GETOPERANDS (VmPtr
);
3393 // Get operand1 index if present
3396 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3397 Index16
= VmReadIndex16 (VmPtr
, 2);
3403 // Get operand1 data we're going to compare to
3405 Op1
= (INT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3406 if (OPERAND1_INDIRECT (Operands
)) {
3408 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3410 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3411 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3413 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3417 // Better not have been an index with direct. That is, CMPI R1 Index,...
3420 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3421 EbcDebugSignalException (
3422 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3423 EXCEPTION_FLAG_ERROR
,
3427 return EFI_UNSUPPORTED
;
3431 // Get immediate data -- 16- or 32-bit sign extended
3433 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3434 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3438 // 16-bit immediate data. Sign extend always.
3440 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3444 // Now do the compare
3447 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3449 // 64 bit comparison
3451 switch (Opcode
& OPCODE_M_OPCODE
) {
3453 if (Op1
== (INT64
) Op2
) {
3458 case OPCODE_CMPILTE
:
3459 if (Op1
<= (INT64
) Op2
) {
3464 case OPCODE_CMPIGTE
:
3465 if (Op1
>= (INT64
) Op2
) {
3470 case OPCODE_CMPIULTE
:
3471 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3476 case OPCODE_CMPIUGTE
:
3477 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3487 // 32-bit comparisons
3489 switch (Opcode
& OPCODE_M_OPCODE
) {
3491 if ((INT32
) Op1
== Op2
) {
3496 case OPCODE_CMPILTE
:
3497 if ((INT32
) Op1
<= Op2
) {
3502 case OPCODE_CMPIGTE
:
3503 if ((INT32
) Op1
>= Op2
) {
3508 case OPCODE_CMPIULTE
:
3509 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3514 case OPCODE_CMPIUGTE
:
3515 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3525 // Now set the flag accordingly for the comparison
3528 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3530 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3541 Execute the EBC NOT instruction.s
3544 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3546 @param VmPtr A pointer to a VM context.
3547 @param Op1 Operand 1 from the instruction
3548 @param Op2 Operand 2 from the instruction
3556 IN VM_CONTEXT
*VmPtr
,
3566 Execute the EBC NEG instruction.
3569 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3571 @param VmPtr A pointer to a VM context.
3572 @param Op1 Operand 1 from the instruction
3573 @param Op2 Operand 2 from the instruction
3581 IN VM_CONTEXT
*VmPtr
,
3591 Execute the EBC ADD instruction.
3594 ADD[32|64] {@}R1, {@}R2 {Index16}
3596 @param VmPtr A pointer to a VM context.
3597 @param Op1 Operand 1 from the instruction
3598 @param Op2 Operand 2 from the instruction
3606 IN VM_CONTEXT
*VmPtr
,
3616 Execute the EBC SUB instruction.
3619 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3621 @param VmPtr A pointer to a VM context.
3622 @param Op1 Operand 1 from the instruction
3623 @param Op2 Operand 2 from the instruction
3631 IN VM_CONTEXT
*VmPtr
,
3636 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3637 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3639 return (UINT64
) ((INT64
) ((INT32
) Op1
- (INT32
) Op2
));
3645 Execute the EBC MUL instruction.
3648 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3650 @param VmPtr A pointer to a VM context.
3651 @param Op1 Operand 1 from the instruction
3652 @param Op2 Operand 2 from the instruction
3660 IN VM_CONTEXT
*VmPtr
,
3665 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3666 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3668 return (UINT64
) ((INT64
) ((INT32
) Op1
* (INT32
) Op2
));
3674 Execute the EBC MULU instruction
3677 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3679 @param VmPtr A pointer to a VM context.
3680 @param Op1 Operand 1 from the instruction
3681 @param Op2 Operand 2 from the instruction
3683 @return (unsigned)Op1 * (unsigned)Op2
3689 IN VM_CONTEXT
*VmPtr
,
3694 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3695 return MultU64x64 (Op1
, Op2
);
3697 return (UINT64
) ((UINT32
) Op1
* (UINT32
) Op2
);
3703 Execute the EBC DIV instruction.
3706 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3708 @param VmPtr A pointer to a VM context.
3709 @param Op1 Operand 1 from the instruction
3710 @param Op2 Operand 2 from the instruction
3718 IN VM_CONTEXT
*VmPtr
,
3726 // Check for divide-by-0
3729 EbcDebugSignalException (
3730 EXCEPT_EBC_DIVIDE_ERROR
,
3731 EXCEPTION_FLAG_FATAL
,
3737 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3738 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3740 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3747 Execute the EBC DIVU instruction
3750 DIVU[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 (unsigned)Op1 / (unsigned)Op2
3762 IN VM_CONTEXT
*VmPtr
,
3770 // Check for divide-by-0
3773 EbcDebugSignalException (
3774 EXCEPT_EBC_DIVIDE_ERROR
,
3775 EXCEPTION_FLAG_FATAL
,
3781 // Get the destination register
3783 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3784 return (UINT64
) (DivU64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
));
3786 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3793 Execute the EBC MOD instruction.
3796 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3798 @param VmPtr A pointer to a VM context.
3799 @param Op1 Operand 1 from the instruction
3800 @param Op2 Operand 2 from the instruction
3802 @return Op1 MODULUS Op2
3808 IN VM_CONTEXT
*VmPtr
,
3816 // Check for divide-by-0
3819 EbcDebugSignalException (
3820 EXCEPT_EBC_DIVIDE_ERROR
,
3821 EXCEPTION_FLAG_FATAL
,
3826 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3833 Execute the EBC MODU instruction.
3836 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3838 @param VmPtr A pointer to a VM context.
3839 @param Op1 Operand 1 from the instruction
3840 @param Op2 Operand 2 from the instruction
3842 @return Op1 UNSIGNED_MODULUS Op2
3848 IN VM_CONTEXT
*VmPtr
,
3856 // Check for divide-by-0
3859 EbcDebugSignalException (
3860 EXCEPT_EBC_DIVIDE_ERROR
,
3861 EXCEPTION_FLAG_FATAL
,
3866 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3873 Execute the EBC AND instruction.
3876 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3878 @param VmPtr A pointer to a VM context.
3879 @param Op1 Operand 1 from the instruction
3880 @param Op2 Operand 2 from the instruction
3888 IN VM_CONTEXT
*VmPtr
,
3898 Execute the EBC OR instruction.
3901 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3903 @param VmPtr A pointer to a VM context.
3904 @param Op1 Operand 1 from the instruction
3905 @param Op2 Operand 2 from the instruction
3913 IN VM_CONTEXT
*VmPtr
,
3923 Execute the EBC XOR instruction.
3926 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3928 @param VmPtr A pointer to a VM context.
3929 @param Op1 Operand 1 from the instruction
3930 @param Op2 Operand 2 from the instruction
3938 IN VM_CONTEXT
*VmPtr
,
3948 Execute the EBC SHL shift left instruction.
3951 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3953 @param VmPtr A pointer to a VM context.
3954 @param Op1 Operand 1 from the instruction
3955 @param Op2 Operand 2 from the instruction
3963 IN VM_CONTEXT
*VmPtr
,
3968 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3969 return LShiftU64 (Op1
, (UINTN
)Op2
);
3971 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3977 Execute the EBC SHR instruction.
3980 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3982 @param VmPtr A pointer to a VM context.
3983 @param Op1 Operand 1 from the instruction
3984 @param Op2 Operand 2 from the instruction
3986 @return Op1 >> Op2 (unsigned operands)
3992 IN VM_CONTEXT
*VmPtr
,
3997 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3998 return RShiftU64 (Op1
, (UINTN
)Op2
);
4000 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
4006 Execute the EBC ASHR instruction.
4009 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
4011 @param VmPtr A pointer to a VM context.
4012 @param Op1 Operand 1 from the instruction
4013 @param Op2 Operand 2 from the instruction
4015 @return Op1 >> Op2 (signed)
4021 IN VM_CONTEXT
*VmPtr
,
4026 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
4027 return ARShiftU64 (Op1
, (UINTN
)Op2
);
4029 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
4035 Execute the EBC EXTNDB instruction to sign-extend a byte value.
4038 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
4040 @param VmPtr A pointer to a VM context.
4041 @param Op1 Operand 1 from the instruction
4042 @param Op2 Operand 2 from the instruction
4044 @return (INT64)(INT8)Op2
4050 IN VM_CONTEXT
*VmPtr
,
4058 // Convert to byte, then return as 64-bit signed value to let compiler
4059 // sign-extend the value
4062 Data64
= (INT64
) Data8
;
4064 return (UINT64
) Data64
;
4069 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
4072 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
4074 @param VmPtr A pointer to a VM context.
4075 @param Op1 Operand 1 from the instruction
4076 @param Op2 Operand 2 from the instruction
4078 @return (INT64)(INT16)Op2
4084 IN VM_CONTEXT
*VmPtr
,
4092 // Convert to word, then return as 64-bit signed value to let compiler
4093 // sign-extend the value
4095 Data16
= (INT16
) Op2
;
4096 Data64
= (INT64
) Data16
;
4098 return (UINT64
) Data64
;
4101 // Execute the EBC EXTNDD instruction.
4103 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4104 // EXTNDD Dest, Source
4106 // Operation: Dest <- SignExtended((DWORD)Source))
4110 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4113 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4115 @param VmPtr A pointer to a VM context.
4116 @param Op1 Operand 1 from the instruction
4117 @param Op2 Operand 2 from the instruction
4119 @return (INT64)(INT32)Op2
4125 IN VM_CONTEXT
*VmPtr
,
4133 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4134 // sign-extend the value
4136 Data32
= (INT32
) Op2
;
4137 Data64
= (INT64
) Data32
;
4139 return (UINT64
) Data64
;
4144 Execute all the EBC signed data manipulation instructions.
4145 Since the EBC data manipulation instructions all have the same basic form,
4146 they can share the code that does the fetch of operands and the write-back
4147 of the result. This function performs the fetch of the operands (even if
4148 both are not needed to be fetched, like NOT instruction), dispatches to the
4149 appropriate subfunction, then writes back the returned result.
4152 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4154 @param VmPtr A pointer to VM context.
4156 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4157 @retval EFI_SUCCESS The instruction is executed successfully.
4162 ExecuteSignedDataManip (
4163 IN VM_CONTEXT
*VmPtr
4167 // Just call the data manipulation function with a flag indicating this
4168 // is a signed operation.
4170 return ExecuteDataManip (VmPtr
, TRUE
);
4175 Execute all the EBC unsigned data manipulation instructions.
4176 Since the EBC data manipulation instructions all have the same basic form,
4177 they can share the code that does the fetch of operands and the write-back
4178 of the result. This function performs the fetch of the operands (even if
4179 both are not needed to be fetched, like NOT instruction), dispatches to the
4180 appropriate subfunction, then writes back the returned result.
4183 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4185 @param VmPtr A pointer to VM context.
4187 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4188 @retval EFI_SUCCESS The instruction is executed successfully.
4193 ExecuteUnsignedDataManip (
4194 IN VM_CONTEXT
*VmPtr
4198 // Just call the data manipulation function with a flag indicating this
4199 // is not a signed operation.
4201 return ExecuteDataManip (VmPtr
, FALSE
);
4206 Execute all the EBC data manipulation instructions.
4207 Since the EBC data manipulation instructions all have the same basic form,
4208 they can share the code that does the fetch of operands and the write-back
4209 of the result. This function performs the fetch of the operands (even if
4210 both are not needed to be fetched, like NOT instruction), dispatches to the
4211 appropriate subfunction, then writes back the returned result.
4214 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4216 @param VmPtr A pointer to VM context.
4217 @param IsSignedOp Indicates whether the operand is signed or not.
4219 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4220 @retval EFI_SUCCESS The instruction is executed successfully.
4226 IN VM_CONTEXT
*VmPtr
,
4227 IN BOOLEAN IsSignedOp
4238 // Get opcode and operands
4240 Opcode
= GETOPCODE (VmPtr
);
4241 Operands
= GETOPERANDS (VmPtr
);
4244 // Determine if we have immediate data by the opcode
4246 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4248 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4250 if (OPERAND2_INDIRECT (Operands
)) {
4251 Index16
= VmReadIndex16 (VmPtr
, 2);
4253 Index16
= VmReadImmed16 (VmPtr
, 2);
4262 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4264 Op2
= (UINT64
) VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
4265 if (OPERAND2_INDIRECT (Operands
)) {
4267 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4269 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4270 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4273 // Read as signed value where appropriate.
4276 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4278 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4282 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4284 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4286 Op2
= (UINT64
) ((UINT32
) Op2
);
4291 // Get operand1 (destination and sometimes also an actual operand)
4294 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4295 if (OPERAND1_INDIRECT (Operands
)) {
4296 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4297 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4300 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4302 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4306 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4308 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4310 Op1
= (UINT64
) ((UINT32
) Op1
);
4315 // Dispatch to the computation function
4317 if (((Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
) >=
4318 (sizeof (mDataManipDispatchTable
) / sizeof (mDataManipDispatchTable
[0]))
4320 EbcDebugSignalException (
4321 EXCEPT_EBC_INVALID_OPCODE
,
4322 EXCEPTION_FLAG_ERROR
,
4326 // Advance and return
4329 return EFI_UNSUPPORTED
;
4331 Op2
= mDataManipDispatchTable
[(Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
](VmPtr
, Op1
, Op2
);
4334 // Write back the result.
4336 if (OPERAND1_INDIRECT (Operands
)) {
4337 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4338 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4339 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4341 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4345 // Storage back to a register. Write back, clearing upper bits (as per
4346 // the specification) if 32-bit operation.
4348 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
4349 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4350 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4354 // Advance the instruction pointer
4362 Execute the EBC LOADSP instruction.
4367 @param VmPtr A pointer to a VM context.
4369 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4370 @retval EFI_SUCCESS The instruction is executed successfully.
4376 IN VM_CONTEXT
*VmPtr
4384 Operands
= GETOPERANDS (VmPtr
);
4389 switch (OPERAND1_REGNUM (Operands
)) {
4395 // Spec states that this instruction will not modify reserved bits in
4396 // the flags register.
4398 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4402 EbcDebugSignalException (
4403 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4404 EXCEPTION_FLAG_WARNING
,
4408 return EFI_UNSUPPORTED
;
4417 Execute the EBC STORESP instruction.
4420 STORESP Rx, FLAGS|IP
4422 @param VmPtr A pointer to a VM context.
4424 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4425 @retval EFI_SUCCESS The instruction is executed successfully.
4431 IN VM_CONTEXT
*VmPtr
4439 Operands
= GETOPERANDS (VmPtr
);
4444 switch (OPERAND2_REGNUM (Operands
)) {
4450 // Retrieve the value in the flags register, then clear reserved bits
4452 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4456 // Get IP -- address of following instruction
4459 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4463 EbcDebugSignalException (
4464 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4465 EXCEPTION_FLAG_WARNING
,
4469 return EFI_UNSUPPORTED
;
4479 Decode a 16-bit index to determine the offset. Given an index value:
4482 b14:12 - number of bits in this index assigned to natural units (=a)
4483 ba:11 - constant units = ConstUnits
4484 b0:a - natural units = NaturalUnits
4486 Given this info, the offset can be computed by:
4487 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4489 Max offset is achieved with index = 0x7FFF giving an offset of
4490 0x27B (32-bit machine) or 0x477 (64-bit machine).
4491 Min offset is achieved with index =
4493 @param VmPtr A pointer to VM context.
4494 @param CodeOffset Offset from IP of the location of the 16-bit index
4497 @return The decoded offset.
4503 IN VM_CONTEXT
*VmPtr
,
4504 IN UINT32 CodeOffset
4515 // First read the index from the code stream
4517 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4520 // Get the mask for NaturalUnits. First get the number of bits from the index.
4522 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4525 // Scale it for 16-bit indexes
4530 // Now using the number of bits, create a mask.
4532 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4535 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4537 NaturalUnits
= (INT16
) (Index
&~Mask
);
4540 // Now compute ConstUnits
4542 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4544 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4549 if ((Index
& 0x8000) != 0) {
4551 // Do it the hard way to work around a bogus compiler warning
4553 // Offset = -1 * Offset;
4555 Offset
= (INT16
) ((INT32
) Offset
* -1);
4563 Decode a 32-bit index to determine the offset.
4565 @param VmPtr A pointer to VM context.
4566 @param CodeOffset Offset from IP of the location of the 32-bit index
4569 @return Converted index per EBC VM specification.
4575 IN VM_CONTEXT
*VmPtr
,
4576 IN UINT32 CodeOffset
4586 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4589 // Get the mask for NaturalUnits. First get the number of bits from the index.
4591 NBits
= (Index
& 0x70000000) >> 28;
4594 // Scale it for 32-bit indexes
4599 // Now using the number of bits, create a mask.
4601 Mask
= (INT32
)~0 << NBits
;
4604 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4606 NaturalUnits
= Index
&~Mask
;
4609 // Now compute ConstUnits
4611 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4613 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4618 if ((Index
& 0x80000000) != 0) {
4619 Offset
= Offset
* -1;
4627 Decode a 64-bit index to determine the offset.
4629 @param VmPtr A pointer to VM context.s
4630 @param CodeOffset Offset from IP of the location of the 64-bit index
4633 @return Converted index per EBC VM specification
4639 IN VM_CONTEXT
*VmPtr
,
4640 IN UINT32 CodeOffset
4650 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4653 // Get the mask for NaturalUnits. First get the number of bits from the index.
4655 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4658 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4660 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4663 // Now using the number of bits, create a mask.
4665 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4668 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4670 NaturalUnits
= Index
&~Mask
;
4673 // Now compute ConstUnits
4675 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4677 Offset
= MultU64x64 (NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4682 if ((Index
& 0x8000000000000000ULL
) != 0) {
4683 Offset
= MultS64x64 (Offset
, -1);
4691 Writes 8-bit data to memory address.
4693 This routine is called by the EBC data
4694 movement instructions that write to memory. Since these writes
4695 may be to the stack, which looks like (high address on top) this,
4697 [EBC entry point arguments]
4701 we need to detect all attempts to write to the EBC entry point argument
4702 stack area and adjust the address (which will initially point into the
4703 VM stack) to point into the EBC entry point arguments.
4705 @param VmPtr A pointer to a VM context.
4706 @param Addr Adddress to write to.
4707 @param Data Value to write to Addr.
4709 @retval EFI_SUCCESS The instruction is executed successfully.
4710 @retval Other Some error occurs when writing data to the address.
4716 IN VM_CONTEXT
*VmPtr
,
4722 // Convert the address if it's in the stack gap
4724 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4725 *(UINT8
*) Addr
= Data
;
4730 Writes 16-bit data to memory address.
4732 This routine is called by the EBC data
4733 movement instructions that write to memory. Since these writes
4734 may be to the stack, which looks like (high address on top) this,
4736 [EBC entry point arguments]
4740 we need to detect all attempts to write to the EBC entry point argument
4741 stack area and adjust the address (which will initially point into the
4742 VM stack) to point into the EBC entry point arguments.
4744 @param VmPtr A pointer to a VM context.
4745 @param Addr Adddress to write to.
4746 @param Data Value to write to Addr.
4748 @retval EFI_SUCCESS The instruction is executed successfully.
4749 @retval Other Some error occurs when writing data to the address.
4755 IN VM_CONTEXT
*VmPtr
,
4763 // Convert the address if it's in the stack gap
4765 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4768 // Do a simple write if aligned
4770 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4771 *(UINT16
*) Addr
= Data
;
4774 // Write as two bytes
4777 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4782 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4794 Writes 32-bit data to memory address.
4796 This routine is called by the EBC data
4797 movement instructions that write to memory. Since these writes
4798 may be to the stack, which looks like (high address on top) this,
4800 [EBC entry point arguments]
4804 we need to detect all attempts to write to the EBC entry point argument
4805 stack area and adjust the address (which will initially point into the
4806 VM stack) to point into the EBC entry point arguments.
4808 @param VmPtr A pointer to a VM context.
4809 @param Addr Adddress to write to.
4810 @param Data Value to write to Addr.
4812 @retval EFI_SUCCESS The instruction is executed successfully.
4813 @retval Other Some error occurs when writing data to the address.
4819 IN VM_CONTEXT
*VmPtr
,
4827 // Convert the address if it's in the stack gap
4829 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4832 // Do a simple write if aligned
4834 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4835 *(UINT32
*) Addr
= Data
;
4838 // Write as two words
4841 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4846 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4858 Writes 64-bit data to memory address.
4860 This routine is called by the EBC data
4861 movement instructions that write to memory. Since these writes
4862 may be to the stack, which looks like (high address on top) this,
4864 [EBC entry point arguments]
4868 we need to detect all attempts to write to the EBC entry point argument
4869 stack area and adjust the address (which will initially point into the
4870 VM stack) to point into the EBC entry point arguments.
4872 @param VmPtr A pointer to a VM context.
4873 @param Addr Adddress to write to.
4874 @param Data Value to write to Addr.
4876 @retval EFI_SUCCESS The instruction is executed successfully.
4877 @retval Other Some error occurs when writing data to the address.
4882 IN VM_CONTEXT
*VmPtr
,
4891 // Convert the address if it's in the stack gap
4893 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4896 // Do a simple write if aligned
4898 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4899 *(UINT64
*) Addr
= Data
;
4902 // Write as two 32-bit words
4905 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4910 Data32
= (UINT32
) (((UINT32
*) &Data
)[1]);
4911 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), Data32
)) != EFI_SUCCESS
) {
4923 Writes UINTN data to memory address.
4925 This routine is called by the EBC data
4926 movement instructions that write to memory. Since these writes
4927 may be to the stack, which looks like (high address on top) this,
4929 [EBC entry point arguments]
4933 we need to detect all attempts to write to the EBC entry point argument
4934 stack area and adjust the address (which will initially point into the
4935 VM stack) to point into the EBC entry point arguments.
4937 @param VmPtr A pointer to a VM context.
4938 @param Addr Adddress to write to.
4939 @param Data Value to write to Addr.
4941 @retval EFI_SUCCESS The instruction is executed successfully.
4942 @retval Other Some error occurs when writing data to the address.
4947 IN VM_CONTEXT
*VmPtr
,
4955 Status
= EFI_SUCCESS
;
4958 // Convert the address if it's in the stack gap
4960 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4963 // Do a simple write if aligned
4965 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4966 *(UINTN
*) Addr
= Data
;
4968 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4970 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4972 Data
= (UINTN
)RShiftU64 ((UINT64
)Data
, 32);
4981 Reads 8-bit immediate value at the offset.
4983 This routine is called by the EBC execute
4984 functions to read EBC immediate values from the code stream.
4985 Since we can't assume alignment, each tries to read in the biggest
4986 chunks size available, but will revert to smaller reads if necessary.
4988 @param VmPtr A pointer to a VM context.
4989 @param Offset offset from IP of the code bytes to read.
4991 @return Signed data of the requested size from the specified address.
4997 IN VM_CONTEXT
*VmPtr
,
5002 // Simply return the data in flat memory space
5004 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
5008 Reads 16-bit immediate value at the offset.
5010 This routine is called by the EBC execute
5011 functions to read EBC immediate values from the code stream.
5012 Since we can't assume alignment, each tries to read in the biggest
5013 chunks size available, but will revert to smaller reads if necessary.
5015 @param VmPtr A pointer to a VM context.
5016 @param Offset offset from IP of the code bytes to read.
5018 @return Signed data of the requested size from the specified address.
5024 IN VM_CONTEXT
*VmPtr
,
5029 // Read direct if aligned
5031 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
5032 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
5035 // All code word reads should be aligned
5037 EbcDebugSignalException (
5038 EXCEPT_EBC_ALIGNMENT_CHECK
,
5039 EXCEPTION_FLAG_WARNING
,
5044 // Return unaligned data
5046 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5051 Reads 32-bit immediate value at the offset.
5053 This routine is called by the EBC execute
5054 functions to read EBC immediate values from the code stream.
5055 Since we can't assume alignment, each tries to read in the biggest
5056 chunks size available, but will revert to smaller reads if necessary.
5058 @param VmPtr A pointer to a VM context.
5059 @param Offset offset from IP of the code bytes to read.
5061 @return Signed data of the requested size from the specified address.
5067 IN VM_CONTEXT
*VmPtr
,
5074 // Read direct if aligned
5076 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5077 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
5080 // Return unaligned data
5082 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5083 Data
|= (UINT32
) (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5089 Reads 64-bit immediate value at the offset.
5091 This routine is called by the EBC execute
5092 functions to read EBC immediate values from the code stream.
5093 Since we can't assume alignment, each tries to read in the biggest
5094 chunks size available, but will revert to smaller reads if necessary.
5096 @param VmPtr A pointer to a VM context.
5097 @param Offset offset from IP of the code bytes to read.
5099 @return Signed data of the requested size from the specified address.
5105 IN VM_CONTEXT
*VmPtr
,
5114 // Read direct if aligned
5116 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5117 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5120 // Return unaligned data.
5122 Ptr
= (UINT8
*) &Data64
;
5123 Data32
= VmReadCode32 (VmPtr
, Offset
);
5124 *(UINT32
*) Ptr
= Data32
;
5125 Ptr
+= sizeof (Data32
);
5126 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5127 *(UINT32
*) Ptr
= Data32
;
5133 Reads 16-bit unsinged data from the code stream.
5135 This routine provides the ability to read raw unsigned data from the code
5138 @param VmPtr A pointer to VM context
5139 @param Offset Offset from current IP to the raw data to read.
5141 @return The raw unsigned 16-bit value from the code stream.
5147 IN VM_CONTEXT
*VmPtr
,
5152 // Read direct if aligned
5154 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5155 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5158 // All code word reads should be aligned
5160 EbcDebugSignalException (
5161 EXCEPT_EBC_ALIGNMENT_CHECK
,
5162 EXCEPTION_FLAG_WARNING
,
5167 // Return unaligned data
5169 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5174 Reads 32-bit unsinged data from the code stream.
5176 This routine provides the ability to read raw unsigned data from the code
5179 @param VmPtr A pointer to VM context
5180 @param Offset Offset from current IP to the raw data to read.
5182 @return The raw unsigned 32-bit value from the code stream.
5188 IN VM_CONTEXT
*VmPtr
,
5194 // Read direct if aligned
5196 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5197 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5200 // Return unaligned data
5202 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5203 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5209 Reads 64-bit unsinged data from the code stream.
5211 This routine provides the ability to read raw unsigned data from the code
5214 @param VmPtr A pointer to VM context
5215 @param Offset Offset from current IP to the raw data to read.
5217 @return The raw unsigned 64-bit value from the code stream.
5223 IN VM_CONTEXT
*VmPtr
,
5232 // Read direct if aligned
5234 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5235 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5238 // Return unaligned data.
5240 Ptr
= (UINT8
*) &Data64
;
5241 Data32
= VmReadCode32 (VmPtr
, Offset
);
5242 *(UINT32
*) Ptr
= Data32
;
5243 Ptr
+= sizeof (Data32
);
5244 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5245 *(UINT32
*) Ptr
= Data32
;
5251 Reads 8-bit data form the memory address.
5253 @param VmPtr A pointer to VM context.
5254 @param Addr The memory address.
5256 @return The 8-bit value from the memory adress.
5262 IN VM_CONTEXT
*VmPtr
,
5267 // Convert the address if it's in the stack gap
5269 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5271 // Simply return the data in flat memory space
5273 return * (UINT8
*) Addr
;
5277 Reads 16-bit data form the memory address.
5279 @param VmPtr A pointer to VM context.
5280 @param Addr The memory address.
5282 @return The 16-bit value from the memory adress.
5288 IN VM_CONTEXT
*VmPtr
,
5293 // Convert the address if it's in the stack gap
5295 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5297 // Read direct if aligned
5299 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5300 return * (UINT16
*) Addr
;
5303 // Return unaligned data
5305 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5309 Reads 32-bit data form the memory address.
5311 @param VmPtr A pointer to VM context.
5312 @param Addr The memory address.
5314 @return The 32-bit value from the memory adress.
5320 IN VM_CONTEXT
*VmPtr
,
5327 // Convert the address if it's in the stack gap
5329 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5331 // Read direct if aligned
5333 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5334 return * (UINT32
*) Addr
;
5337 // Return unaligned data
5339 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5340 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5345 Reads 64-bit data form the memory address.
5347 @param VmPtr A pointer to VM context.
5348 @param Addr The memory address.
5350 @return The 64-bit value from the memory adress.
5356 IN VM_CONTEXT
*VmPtr
,
5364 // Convert the address if it's in the stack gap
5366 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5369 // Read direct if aligned
5371 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5372 return * (UINT64
*) Addr
;
5375 // Return unaligned data. Assume little endian.
5377 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
);
5378 Data32
= VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5379 *(UINT32
*) ((UINT32
*) &Data
+ 1) = Data32
;
5385 Given an address that EBC is going to read from or write to, return
5386 an appropriate address that accounts for a gap in the stack.
5387 The stack for this application looks like this (high addr on top)
5388 [EBC entry point arguments]
5391 The EBC assumes that its arguments are at the top of its stack, which
5392 is where the VM stack is really. Therefore if the EBC does memory
5393 accesses into the VM stack area, then we need to convert the address
5394 to point to the EBC entry point arguments area. Do this here.
5396 @param VmPtr A Pointer to VM context.
5397 @param Addr Address of interest
5399 @return The unchanged address if it's not in the VM stack region. Otherwise,
5400 adjust for the stack gap and return the modified address.
5406 IN VM_CONTEXT
*VmPtr
,
5410 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5416 Read a natural value from memory. May or may not be aligned.
5418 @param VmPtr current VM context
5419 @param Addr the address to read from
5421 @return The natural value at address Addr.
5427 IN VM_CONTEXT
*VmPtr
,
5432 volatile UINT32 Size
;
5436 // Convert the address if it's in the stack gap
5438 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5440 // Read direct if aligned
5442 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5443 return * (UINTN
*) Addr
;
5446 // Return unaligned data
5449 FromPtr
= (UINT8
*) Addr
;
5450 ToPtr
= (UINT8
*) &Data
;
5452 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5462 Returns the version of the EBC virtual machine.
5464 @return The 64-bit version of EBC virtual machine.
5472 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));