]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/EbcDxe/EbcExecute.c
MdeModulePkg: INF/DEC file updates to EDK II packages
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcExecute.c
CommitLineData
fb0b259e 1/** @file\r
2 Contains code that implements the virtual machine.\r
53c71d09 3\r
4e1005ec 4Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
fb0b259e 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
53c71d09 9\r
fb0b259e 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
53c71d09 12\r
fb0b259e 13**/\r
53c71d09 14\r
15#include "EbcInt.h"\r
16#include "EbcExecute.h"\r
17\r
18\r
19//\r
20// Define some useful data size constants to allow switch statements based on\r
21// size of operands or data.\r
22//\r
23#define DATA_SIZE_INVALID 0\r
24#define DATA_SIZE_8 1\r
25#define DATA_SIZE_16 2\r
26#define DATA_SIZE_32 4\r
27#define DATA_SIZE_64 8\r
28#define DATA_SIZE_N 48 // 4 or 8\r
29//\r
30// Structure we'll use to dispatch opcodes to execute functions.\r
31//\r
32typedef struct {\r
33 EFI_STATUS (*ExecuteFunction) (IN VM_CONTEXT * VmPtr);\r
34}\r
35VM_TABLE_ENTRY;\r
36\r
37typedef\r
38UINT64\r
39(*DATA_MANIP_EXEC_FUNCTION) (\r
40 IN VM_CONTEXT * VmPtr,\r
41 IN UINT64 Op1,\r
42 IN UINT64 Op2\r
43 );\r
44\r
8e3bc754 45/**\r
46 Decode a 16-bit index to determine the offset. Given an index value:\r
47\r
48 b15 - sign bit\r
49 b14:12 - number of bits in this index assigned to natural units (=a)\r
50 ba:11 - constant units = ConstUnits\r
51 b0:a - natural units = NaturalUnits\r
34e4e297 52\r
8e3bc754 53 Given this info, the offset can be computed by:\r
54 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))\r
55\r
56 Max offset is achieved with index = 0x7FFF giving an offset of\r
57 0x27B (32-bit machine) or 0x477 (64-bit machine).\r
34e4e297 58 Min offset is achieved with index =\r
8e3bc754 59\r
60 @param VmPtr A pointer to VM context.\r
61 @param CodeOffset Offset from IP of the location of the 16-bit index\r
62 to decode.\r
63\r
64 @return The decoded offset.\r
65\r
66**/\r
53c71d09 67INT16\r
68VmReadIndex16 (\r
ea7cb08c 69 IN VM_CONTEXT *VmPtr,\r
70 IN UINT32 CodeOffset\r
53c71d09 71 );\r
72\r
8e3bc754 73/**\r
74 Decode a 32-bit index to determine the offset.\r
75\r
76 @param VmPtr A pointer to VM context.\r
77 @param CodeOffset Offset from IP of the location of the 32-bit index\r
78 to decode.\r
79\r
80 @return Converted index per EBC VM specification.\r
81\r
82**/\r
53c71d09 83INT32\r
84VmReadIndex32 (\r
ea7cb08c 85 IN VM_CONTEXT *VmPtr,\r
86 IN UINT32 CodeOffset\r
53c71d09 87 );\r
88\r
8e3bc754 89/**\r
90 Decode a 64-bit index to determine the offset.\r
91\r
92 @param VmPtr A pointer to VM context.s\r
93 @param CodeOffset Offset from IP of the location of the 64-bit index\r
94 to decode.\r
95\r
96 @return Converted index per EBC VM specification\r
97\r
98**/\r
53c71d09 99INT64\r
100VmReadIndex64 (\r
ea7cb08c 101 IN VM_CONTEXT *VmPtr,\r
102 IN UINT32 CodeOffset\r
53c71d09 103 );\r
104\r
8e3bc754 105/**\r
106 Reads 8-bit data form the memory address.\r
107\r
108 @param VmPtr A pointer to VM context.\r
109 @param Addr The memory address.\r
110\r
48557c65 111 @return The 8-bit value from the memory address.\r
8e3bc754 112\r
113**/\r
53c71d09 114UINT8\r
115VmReadMem8 (\r
ea7cb08c 116 IN VM_CONTEXT *VmPtr,\r
117 IN UINTN Addr\r
53c71d09 118 );\r
119\r
8e3bc754 120/**\r
121 Reads 16-bit data form the memory address.\r
122\r
123 @param VmPtr A pointer to VM context.\r
124 @param Addr The memory address.\r
125\r
48557c65 126 @return The 16-bit value from the memory address.\r
8e3bc754 127\r
128**/\r
53c71d09 129UINT16\r
130VmReadMem16 (\r
131 IN VM_CONTEXT *VmPtr,\r
132 IN UINTN Addr\r
133 );\r
134\r
8e3bc754 135/**\r
136 Reads 32-bit data form the memory address.\r
137\r
138 @param VmPtr A pointer to VM context.\r
139 @param Addr The memory address.\r
140\r
48557c65 141 @return The 32-bit value from the memory address.\r
8e3bc754 142\r
143**/\r
53c71d09 144UINT32\r
145VmReadMem32 (\r
146 IN VM_CONTEXT *VmPtr,\r
147 IN UINTN Addr\r
148 );\r
149\r
8e3bc754 150/**\r
151 Reads 64-bit data form the memory address.\r
152\r
153 @param VmPtr A pointer to VM context.\r
154 @param Addr The memory address.\r
155\r
48557c65 156 @return The 64-bit value from the memory address.\r
8e3bc754 157\r
158**/\r
53c71d09 159UINT64\r
160VmReadMem64 (\r
ea7cb08c 161 IN VM_CONTEXT *VmPtr,\r
162 IN UINTN Addr\r
53c71d09 163 );\r
164\r
8e3bc754 165/**\r
166 Read a natural value from memory. May or may not be aligned.\r
167\r
168 @param VmPtr current VM context\r
169 @param Addr the address to read from\r
170\r
171 @return The natural value at address Addr.\r
172\r
173**/\r
53c71d09 174UINTN\r
175VmReadMemN (\r
ea7cb08c 176 IN VM_CONTEXT *VmPtr,\r
177 IN UINTN Addr\r
53c71d09 178 );\r
179\r
8e3bc754 180/**\r
181 Writes 8-bit data to memory address.\r
34e4e297 182\r
8e3bc754 183 This routine is called by the EBC data\r
184 movement instructions that write to memory. Since these writes\r
185 may be to the stack, which looks like (high address on top) this,\r
186\r
187 [EBC entry point arguments]\r
188 [VM stack]\r
189 [EBC stack]\r
190\r
191 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 192 stack area and adjust the address (which will initially point into the\r
8e3bc754 193 VM stack) to point into the EBC entry point arguments.\r
194\r
195 @param VmPtr A pointer to a VM context.\r
48557c65 196 @param Addr Address to write to.\r
8e3bc754 197 @param Data Value to write to Addr.\r
198\r
34e4e297 199 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 200 @retval Other Some error occurs when writing data to the address.\r
201\r
202**/\r
53c71d09 203EFI_STATUS\r
204VmWriteMem8 (\r
ea7cb08c 205 IN VM_CONTEXT *VmPtr,\r
206 IN UINTN Addr,\r
207 IN UINT8 Data\r
53c71d09 208 );\r
209\r
8e3bc754 210/**\r
211 Writes 16-bit data to memory address.\r
34e4e297 212\r
8e3bc754 213 This routine is called by the EBC data\r
214 movement instructions that write to memory. Since these writes\r
215 may be to the stack, which looks like (high address on top) this,\r
216\r
217 [EBC entry point arguments]\r
218 [VM stack]\r
219 [EBC stack]\r
220\r
221 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 222 stack area and adjust the address (which will initially point into the\r
8e3bc754 223 VM stack) to point into the EBC entry point arguments.\r
224\r
225 @param VmPtr A pointer to a VM context.\r
48557c65 226 @param Addr Address to write to.\r
8e3bc754 227 @param Data Value to write to Addr.\r
228\r
34e4e297 229 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 230 @retval Other Some error occurs when writing data to the address.\r
231\r
232**/\r
53c71d09 233EFI_STATUS\r
234VmWriteMem16 (\r
ea7cb08c 235 IN VM_CONTEXT *VmPtr,\r
236 IN UINTN Addr,\r
237 IN UINT16 Data\r
53c71d09 238 );\r
239\r
8e3bc754 240/**\r
241 Writes 32-bit data to memory address.\r
34e4e297 242\r
8e3bc754 243 This routine is called by the EBC data\r
244 movement instructions that write to memory. Since these writes\r
245 may be to the stack, which looks like (high address on top) this,\r
246\r
247 [EBC entry point arguments]\r
248 [VM stack]\r
249 [EBC stack]\r
250\r
251 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 252 stack area and adjust the address (which will initially point into the\r
8e3bc754 253 VM stack) to point into the EBC entry point arguments.\r
254\r
255 @param VmPtr A pointer to a VM context.\r
48557c65 256 @param Addr Address to write to.\r
8e3bc754 257 @param Data Value to write to Addr.\r
258\r
34e4e297 259 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 260 @retval Other Some error occurs when writing data to the address.\r
261\r
262**/\r
53c71d09 263EFI_STATUS\r
264VmWriteMem32 (\r
ea7cb08c 265 IN VM_CONTEXT *VmPtr,\r
266 IN UINTN Addr,\r
267 IN UINT32 Data\r
53c71d09 268 );\r
269\r
8e3bc754 270/**\r
48557c65 271 Reads 16-bit unsigned data from the code stream.\r
8e3bc754 272\r
273 This routine provides the ability to read raw unsigned data from the code\r
274 stream.\r
275\r
276 @param VmPtr A pointer to VM context\r
277 @param Offset Offset from current IP to the raw data to read.\r
278\r
279 @return The raw unsigned 16-bit value from the code stream.\r
280\r
281**/\r
53c71d09 282UINT16\r
283VmReadCode16 (\r
284 IN VM_CONTEXT *VmPtr,\r
285 IN UINT32 Offset\r
286 );\r
287\r
8e3bc754 288/**\r
48557c65 289 Reads 32-bit unsigned data from the code stream.\r
8e3bc754 290\r
291 This routine provides the ability to read raw unsigned data from the code\r
292 stream.\r
293\r
294 @param VmPtr A pointer to VM context\r
295 @param Offset Offset from current IP to the raw data to read.\r
296\r
297 @return The raw unsigned 32-bit value from the code stream.\r
298\r
299**/\r
53c71d09 300UINT32\r
301VmReadCode32 (\r
302 IN VM_CONTEXT *VmPtr,\r
303 IN UINT32 Offset\r
304 );\r
305\r
8e3bc754 306/**\r
48557c65 307 Reads 64-bit unsigned data from the code stream.\r
8e3bc754 308\r
309 This routine provides the ability to read raw unsigned data from the code\r
310 stream.\r
311\r
312 @param VmPtr A pointer to VM context\r
313 @param Offset Offset from current IP to the raw data to read.\r
314\r
315 @return The raw unsigned 64-bit value from the code stream.\r
316\r
317**/\r
53c71d09 318UINT64\r
319VmReadCode64 (\r
320 IN VM_CONTEXT *VmPtr,\r
321 IN UINT32 Offset\r
322 );\r
323\r
8e3bc754 324/**\r
325 Reads 8-bit immediate value at the offset.\r
326\r
327 This routine is called by the EBC execute\r
328 functions to read EBC immediate values from the code stream.\r
329 Since we can't assume alignment, each tries to read in the biggest\r
330 chunks size available, but will revert to smaller reads if necessary.\r
331\r
332 @param VmPtr A pointer to a VM context.\r
333 @param Offset offset from IP of the code bytes to read.\r
334\r
335 @return Signed data of the requested size from the specified address.\r
336\r
337**/\r
53c71d09 338INT8\r
339VmReadImmed8 (\r
340 IN VM_CONTEXT *VmPtr,\r
341 IN UINT32 Offset\r
342 );\r
343\r
8e3bc754 344/**\r
345 Reads 16-bit immediate value at the offset.\r
346\r
347 This routine is called by the EBC execute\r
348 functions to read EBC immediate values from the code stream.\r
349 Since we can't assume alignment, each tries to read in the biggest\r
350 chunks size available, but will revert to smaller reads if necessary.\r
351\r
352 @param VmPtr A pointer to a VM context.\r
353 @param Offset offset from IP of the code bytes to read.\r
354\r
355 @return Signed data of the requested size from the specified address.\r
356\r
357**/\r
53c71d09 358INT16\r
359VmReadImmed16 (\r
360 IN VM_CONTEXT *VmPtr,\r
361 IN UINT32 Offset\r
362 );\r
363\r
8e3bc754 364/**\r
365 Reads 32-bit immediate value at the offset.\r
366\r
367 This routine is called by the EBC execute\r
368 functions to read EBC immediate values from the code stream.\r
369 Since we can't assume alignment, each tries to read in the biggest\r
370 chunks size available, but will revert to smaller reads if necessary.\r
371\r
372 @param VmPtr A pointer to a VM context.\r
373 @param Offset offset from IP of the code bytes to read.\r
374\r
375 @return Signed data of the requested size from the specified address.\r
376\r
377**/\r
53c71d09 378INT32\r
379VmReadImmed32 (\r
380 IN VM_CONTEXT *VmPtr,\r
381 IN UINT32 Offset\r
382 );\r
383\r
8e3bc754 384/**\r
385 Reads 64-bit immediate value at the offset.\r
386\r
387 This routine is called by the EBC execute\r
388 functions to read EBC immediate values from the code stream.\r
389 Since we can't assume alignment, each tries to read in the biggest\r
390 chunks size available, but will revert to smaller reads if necessary.\r
391\r
392 @param VmPtr A pointer to a VM context.\r
393 @param Offset offset from IP of the code bytes to read.\r
394\r
395 @return Signed data of the requested size from the specified address.\r
396\r
397**/\r
53c71d09 398INT64\r
399VmReadImmed64 (\r
400 IN VM_CONTEXT *VmPtr,\r
401 IN UINT32 Offset\r
402 );\r
403\r
8e3bc754 404/**\r
405 Given an address that EBC is going to read from or write to, return\r
406 an appropriate address that accounts for a gap in the stack.\r
407 The stack for this application looks like this (high addr on top)\r
408 [EBC entry point arguments]\r
409 [VM stack]\r
410 [EBC stack]\r
411 The EBC assumes that its arguments are at the top of its stack, which\r
412 is where the VM stack is really. Therefore if the EBC does memory\r
413 accesses into the VM stack area, then we need to convert the address\r
414 to point to the EBC entry point arguments area. Do this here.\r
415\r
416 @param VmPtr A Pointer to VM context.\r
417 @param Addr Address of interest\r
418\r
419 @return The unchanged address if it's not in the VM stack region. Otherwise,\r
420 adjust for the stack gap and return the modified address.\r
421\r
422**/\r
53c71d09 423UINTN\r
424ConvertStackAddr (\r
ea7cb08c 425 IN VM_CONTEXT *VmPtr,\r
426 IN UINTN Addr\r
53c71d09 427 );\r
428\r
8e3bc754 429/**\r
430 Execute all the EBC data manipulation instructions.\r
431 Since the EBC data manipulation instructions all have the same basic form,\r
432 they can share the code that does the fetch of operands and the write-back\r
433 of the result. This function performs the fetch of the operands (even if\r
434 both are not needed to be fetched, like NOT instruction), dispatches to the\r
435 appropriate subfunction, then writes back the returned result.\r
436\r
437 Format:\r
438 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
439\r
440 @param VmPtr A pointer to VM context.\r
441 @param IsSignedOp Indicates whether the operand is signed or not.\r
442\r
34e4e297 443 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 444 @retval EFI_SUCCESS The instruction is executed successfully.\r
445\r
446**/\r
53c71d09 447EFI_STATUS\r
448ExecuteDataManip (\r
449 IN VM_CONTEXT *VmPtr,\r
8e3bc754 450 IN BOOLEAN IsSignedOp\r
53c71d09 451 );\r
452\r
453//\r
454// Functions that execute VM opcodes\r
455//\r
8e3bc754 456/**\r
457 Execute the EBC BREAK instruction.\r
458\r
459 @param VmPtr A pointer to a VM context.\r
460\r
461 @retval EFI_SUCCESS The instruction is executed successfully.\r
462\r
463**/\r
53c71d09 464EFI_STATUS\r
465ExecuteBREAK (\r
466 IN VM_CONTEXT *VmPtr\r
467 );\r
468\r
8e3bc754 469/**\r
470 Execute the JMP instruction.\r
471\r
472 Instruction syntax:\r
473 JMP64{cs|cc} Immed64\r
474 JMP32{cs|cc} {@}R1 {Immed32|Index32}\r
34e4e297 475\r
8e3bc754 476 Encoding:\r
477 b0.7 - immediate data present\r
478 b0.6 - 1 = 64 bit immediate data\r
479 0 = 32 bit immediate data\r
480 b1.7 - 1 = conditional\r
481 b1.6 1 = CS (condition set)\r
482 0 = CC (condition clear)\r
483 b1.4 1 = relative address\r
484 0 = absolute address\r
485 b1.3 1 = operand1 indirect\r
486 b1.2-0 operand 1\r
487\r
488 @param VmPtr A pointer to a VM context.\r
489\r
490 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
491 @retval EFI_SUCCESS The instruction is executed successfully.\r
492\r
493**/\r
53c71d09 494EFI_STATUS\r
495ExecuteJMP (\r
496 IN VM_CONTEXT *VmPtr\r
497 );\r
498\r
8e3bc754 499/**\r
500 Execute the EBC JMP8 instruction.\r
501\r
502 Instruction syntax:\r
503 JMP8{cs|cc} Offset/2\r
504\r
505 @param VmPtr A pointer to a VM context.\r
506\r
507 @retval EFI_SUCCESS The instruction is executed successfully.\r
508\r
509**/\r
53c71d09 510EFI_STATUS\r
511ExecuteJMP8 (\r
512 IN VM_CONTEXT *VmPtr\r
513 );\r
514\r
8e3bc754 515/**\r
516 Implements the EBC CALL instruction.\r
517\r
518 Instruction format:\r
519 CALL64 Immed64\r
520 CALL32 {@}R1 {Immed32|Index32}\r
521 CALLEX64 Immed64\r
522 CALLEX16 {@}R1 {Immed32}\r
523\r
524 If Rx == R0, then it's a PC relative call to PC = PC + imm32.\r
525\r
526 @param VmPtr A pointer to a VM context.\r
527\r
528 @retval EFI_SUCCESS The instruction is executed successfully.\r
529\r
530**/\r
53c71d09 531EFI_STATUS\r
532ExecuteCALL (\r
533 IN VM_CONTEXT *VmPtr\r
534 );\r
535\r
8e3bc754 536/**\r
537 Execute the EBC RET instruction.\r
538\r
539 Instruction syntax:\r
540 RET\r
541\r
542 @param VmPtr A pointer to a VM context.\r
543\r
544 @retval EFI_SUCCESS The instruction is executed successfully.\r
545\r
546**/\r
53c71d09 547EFI_STATUS\r
548ExecuteRET (\r
549 IN VM_CONTEXT *VmPtr\r
550 );\r
551\r
8e3bc754 552/**\r
553 Execute the EBC CMP instruction.\r
554\r
555 Instruction syntax:\r
556 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}\r
557\r
558 @param VmPtr A pointer to a VM context.\r
559\r
34e4e297 560 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 561 @retval EFI_SUCCESS The instruction is executed successfully.\r
562\r
563**/\r
53c71d09 564EFI_STATUS\r
565ExecuteCMP (\r
566 IN VM_CONTEXT *VmPtr\r
567 );\r
568\r
8e3bc754 569/**\r
570 Execute the EBC CMPI instruction\r
571\r
572 Instruction syntax:\r
573 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32\r
574\r
575 @param VmPtr A pointer to a VM context.\r
576\r
34e4e297 577 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 578 @retval EFI_SUCCESS The instruction is executed successfully.\r
579\r
580**/\r
53c71d09 581EFI_STATUS\r
582ExecuteCMPI (\r
583 IN VM_CONTEXT *VmPtr\r
584 );\r
585\r
8e3bc754 586/**\r
587 Execute the MOVxx instructions.\r
588\r
589 Instruction format:\r
34e4e297 590\r
8e3bc754 591 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}\r
592 MOVqq {@}R1 {Index64}, {@}R2 {Index64}\r
34e4e297 593\r
8e3bc754 594 Copies contents of [R2] -> [R1], zero extending where required.\r
34e4e297 595\r
8e3bc754 596 First character indicates the size of the move.\r
597 Second character indicates the size of the index(s).\r
34e4e297 598\r
8e3bc754 599 Invalid to have R1 direct with index.\r
600\r
601 @param VmPtr A pointer to a VM context.\r
602\r
603 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
604 @retval EFI_SUCCESS The instruction is executed successfully.\r
605\r
606**/\r
53c71d09 607EFI_STATUS\r
608ExecuteMOVxx (\r
609 IN VM_CONTEXT *VmPtr\r
610 );\r
611\r
8e3bc754 612/**\r
613 Execute the EBC MOVI.\r
614\r
615 Instruction syntax:\r
34e4e297 616\r
8e3bc754 617 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
34e4e297 618\r
8e3bc754 619 First variable character specifies the move size\r
620 Second variable character specifies size of the immediate data\r
34e4e297 621\r
8e3bc754 622 Sign-extend the immediate data to the size of the operation, and zero-extend\r
623 if storing to a register.\r
34e4e297 624\r
8e3bc754 625 Operand1 direct with index/immed is invalid.\r
626\r
627 @param VmPtr A pointer to a VM context.\r
628\r
34e4e297 629 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 630 @retval EFI_SUCCESS The instruction is executed successfully.\r
631\r
632**/\r
53c71d09 633EFI_STATUS\r
634ExecuteMOVI (\r
635 IN VM_CONTEXT *VmPtr\r
636 );\r
637\r
8e3bc754 638/**\r
639 Execute the EBC MOV immediate natural. This instruction moves an immediate\r
640 index value into a register or memory location.\r
641\r
642 Instruction syntax:\r
34e4e297 643\r
8e3bc754 644 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64\r
645\r
646 @param VmPtr A pointer to a VM context.\r
647\r
34e4e297 648 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 649 @retval EFI_SUCCESS The instruction is executed successfully.\r
650\r
651**/\r
53c71d09 652EFI_STATUS\r
653ExecuteMOVIn (\r
654 IN VM_CONTEXT *VmPtr\r
655 );\r
656\r
8e3bc754 657/**\r
658 Execute the EBC MOVREL instruction.\r
659 Dest <- Ip + ImmData\r
660\r
661 Instruction syntax:\r
34e4e297 662\r
8e3bc754 663 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
664\r
665 @param VmPtr A pointer to a VM context.\r
666\r
34e4e297 667 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 668 @retval EFI_SUCCESS The instruction is executed successfully.\r
669\r
670**/\r
53c71d09 671EFI_STATUS\r
672ExecuteMOVREL (\r
673 IN VM_CONTEXT *VmPtr\r
674 );\r
675\r
8e3bc754 676/**\r
677 Execute the EBC PUSHn instruction\r
678\r
679 Instruction syntax:\r
680 PUSHn {@}R1 {Index16|Immed16}\r
681\r
682 @param VmPtr A pointer to a VM context.\r
683\r
684 @retval EFI_SUCCESS The instruction is executed successfully.\r
685\r
686**/\r
53c71d09 687EFI_STATUS\r
688ExecutePUSHn (\r
689 IN VM_CONTEXT *VmPtr\r
690 );\r
691\r
8e3bc754 692/**\r
693 Execute the EBC PUSH instruction.\r
694\r
695 Instruction syntax:\r
696 PUSH[32|64] {@}R1 {Index16|Immed16}\r
697\r
698 @param VmPtr A pointer to a VM context.\r
699\r
700 @retval EFI_SUCCESS The instruction is executed successfully.\r
701\r
702**/\r
53c71d09 703EFI_STATUS\r
704ExecutePUSH (\r
705 IN VM_CONTEXT *VmPtr\r
706 );\r
707\r
8e3bc754 708/**\r
709 Execute the EBC POPn instruction.\r
710\r
711 Instruction syntax:\r
712 POPn {@}R1 {Index16|Immed16}\r
713\r
714 @param VmPtr A pointer to a VM context.\r
715\r
716 @retval EFI_SUCCESS The instruction is executed successfully.\r
717\r
718**/\r
53c71d09 719EFI_STATUS\r
720ExecutePOPn (\r
721 IN VM_CONTEXT *VmPtr\r
722 );\r
723\r
8e3bc754 724/**\r
725 Execute the EBC POP instruction.\r
726\r
727 Instruction syntax:\r
728 POPn {@}R1 {Index16|Immed16}\r
729\r
730 @param VmPtr A pointer to a VM context.\r
731\r
732 @retval EFI_SUCCESS The instruction is executed successfully.\r
733\r
734**/\r
53c71d09 735EFI_STATUS\r
736ExecutePOP (\r
737 IN VM_CONTEXT *VmPtr\r
738 );\r
739\r
8e3bc754 740/**\r
741 Execute all the EBC signed data manipulation instructions.\r
742 Since the EBC data manipulation instructions all have the same basic form,\r
743 they can share the code that does the fetch of operands and the write-back\r
744 of the result. This function performs the fetch of the operands (even if\r
745 both are not needed to be fetched, like NOT instruction), dispatches to the\r
746 appropriate subfunction, then writes back the returned result.\r
747\r
748 Format:\r
749 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
750\r
751 @param VmPtr A pointer to VM context.\r
752\r
34e4e297 753 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 754 @retval EFI_SUCCESS The instruction is executed successfully.\r
755\r
756**/\r
53c71d09 757EFI_STATUS\r
758ExecuteSignedDataManip (\r
ea7cb08c 759 IN VM_CONTEXT *VmPtr\r
53c71d09 760 );\r
761\r
8e3bc754 762/**\r
763 Execute all the EBC unsigned data manipulation instructions.\r
764 Since the EBC data manipulation instructions all have the same basic form,\r
765 they can share the code that does the fetch of operands and the write-back\r
766 of the result. This function performs the fetch of the operands (even if\r
767 both are not needed to be fetched, like NOT instruction), dispatches to the\r
768 appropriate subfunction, then writes back the returned result.\r
769\r
770 Format:\r
771 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
772\r
773 @param VmPtr A pointer to VM context.\r
774\r
34e4e297 775 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 776 @retval EFI_SUCCESS The instruction is executed successfully.\r
777\r
778**/\r
53c71d09 779EFI_STATUS\r
780ExecuteUnsignedDataManip (\r
ea7cb08c 781 IN VM_CONTEXT *VmPtr\r
53c71d09 782 );\r
783\r
8e3bc754 784/**\r
785 Execute the EBC LOADSP instruction.\r
786\r
787 Instruction syntax:\r
788 LOADSP SP1, R2\r
789\r
790 @param VmPtr A pointer to a VM context.\r
791\r
34e4e297 792 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 793 @retval EFI_SUCCESS The instruction is executed successfully.\r
794\r
795**/\r
53c71d09 796EFI_STATUS\r
797ExecuteLOADSP (\r
798 IN VM_CONTEXT *VmPtr\r
799 );\r
800\r
8e3bc754 801/**\r
802 Execute the EBC STORESP instruction.\r
803\r
804 Instruction syntax:\r
805 STORESP Rx, FLAGS|IP\r
806\r
807 @param VmPtr A pointer to a VM context.\r
808\r
34e4e297 809 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 810 @retval EFI_SUCCESS The instruction is executed successfully.\r
811\r
812**/\r
53c71d09 813EFI_STATUS\r
814ExecuteSTORESP (\r
815 IN VM_CONTEXT *VmPtr\r
816 );\r
817\r
8e3bc754 818/**\r
819 Execute the EBC MOVsnw instruction. This instruction loads a signed\r
820 natural value from memory or register to another memory or register. On\r
821 32-bit machines, the value gets sign-extended to 64 bits if the destination\r
822 is a register.\r
823\r
824 Instruction syntax:\r
34e4e297 825\r
8e3bc754 826 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}\r
34e4e297 827\r
8e3bc754 828 0:7 1=>operand1 index present\r
829 0:6 1=>operand2 index present\r
830\r
831 @param VmPtr A pointer to a VM context.\r
832\r
34e4e297 833 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 834 @retval EFI_SUCCESS The instruction is executed successfully.\r
835\r
836**/\r
53c71d09 837EFI_STATUS\r
838ExecuteMOVsnd (\r
839 IN VM_CONTEXT *VmPtr\r
840 );\r
841\r
8e3bc754 842/**\r
843 Execute the EBC MOVsnw instruction. This instruction loads a signed\r
844 natural value from memory or register to another memory or register. On\r
845 32-bit machines, the value gets sign-extended to 64 bits if the destination\r
846 is a register.\r
847\r
848 Instruction syntax:\r
34e4e297 849\r
8e3bc754 850 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}\r
34e4e297 851\r
8e3bc754 852 0:7 1=>operand1 index present\r
853 0:6 1=>operand2 index present\r
854\r
855 @param VmPtr A pointer to a VM context.\r
856\r
34e4e297 857 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 858 @retval EFI_SUCCESS The instruction is executed successfully.\r
859\r
860**/\r
53c71d09 861EFI_STATUS\r
862ExecuteMOVsnw (\r
863 IN VM_CONTEXT *VmPtr\r
864 );\r
865\r
866//\r
867// Data manipulation subfunctions\r
868//\r
8e3bc754 869/**\r
870 Execute the EBC NOT instruction.s\r
871\r
872 Instruction syntax:\r
873 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
874\r
875 @param VmPtr A pointer to a VM context.\r
876 @param Op1 Operand 1 from the instruction\r
877 @param Op2 Operand 2 from the instruction\r
878\r
879 @return ~Op2\r
880\r
881**/\r
53c71d09 882UINT64\r
883ExecuteNOT (\r
ea7cb08c 884 IN VM_CONTEXT *VmPtr,\r
885 IN UINT64 Op1,\r
886 IN UINT64 Op2\r
53c71d09 887 );\r
888\r
8e3bc754 889/**\r
890 Execute the EBC NEG instruction.\r
891\r
892 Instruction syntax:\r
893 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
894\r
895 @param VmPtr A pointer to a VM context.\r
896 @param Op1 Operand 1 from the instruction\r
897 @param Op2 Operand 2 from the instruction\r
898\r
899 @return Op2 * -1\r
900\r
901**/\r
53c71d09 902UINT64\r
903ExecuteNEG (\r
ea7cb08c 904 IN VM_CONTEXT *VmPtr,\r
905 IN UINT64 Op1,\r
906 IN UINT64 Op2\r
53c71d09 907 );\r
908\r
8e3bc754 909/**\r
910 Execute the EBC ADD instruction.\r
911\r
912 Instruction syntax:\r
913 ADD[32|64] {@}R1, {@}R2 {Index16}\r
914\r
915 @param VmPtr A pointer to a VM context.\r
916 @param Op1 Operand 1 from the instruction\r
917 @param Op2 Operand 2 from the instruction\r
918\r
919 @return Op1 + Op2\r
920\r
921**/\r
53c71d09 922UINT64\r
923ExecuteADD (\r
ea7cb08c 924 IN VM_CONTEXT *VmPtr,\r
925 IN UINT64 Op1,\r
926 IN UINT64 Op2\r
53c71d09 927 );\r
928\r
8e3bc754 929/**\r
930 Execute the EBC SUB instruction.\r
931\r
932 Instruction syntax:\r
933 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
934\r
935 @param VmPtr A pointer to a VM context.\r
936 @param Op1 Operand 1 from the instruction\r
937 @param Op2 Operand 2 from the instruction\r
938\r
939 @return Op1 - Op2\r
940\r
941**/\r
53c71d09 942UINT64\r
943ExecuteSUB (\r
ea7cb08c 944 IN VM_CONTEXT *VmPtr,\r
945 IN UINT64 Op1,\r
946 IN UINT64 Op2\r
53c71d09 947 );\r
948\r
8e3bc754 949/**\r
950 Execute the EBC MUL instruction.\r
951\r
952 Instruction syntax:\r
953 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
954\r
955 @param VmPtr A pointer to a VM context.\r
956 @param Op1 Operand 1 from the instruction\r
957 @param Op2 Operand 2 from the instruction\r
958\r
959 @return Op1 * Op2\r
960\r
961**/\r
53c71d09 962UINT64\r
963ExecuteMUL (\r
ea7cb08c 964 IN VM_CONTEXT *VmPtr,\r
965 IN UINT64 Op1,\r
966 IN UINT64 Op2\r
53c71d09 967 );\r
968\r
8e3bc754 969/**\r
970 Execute the EBC MULU instruction\r
971\r
972 Instruction syntax:\r
973 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
974\r
975 @param VmPtr A pointer to a VM context.\r
976 @param Op1 Operand 1 from the instruction\r
977 @param Op2 Operand 2 from the instruction\r
978\r
979 @return (unsigned)Op1 * (unsigned)Op2\r
980\r
981**/\r
53c71d09 982UINT64\r
983ExecuteMULU (\r
ea7cb08c 984 IN VM_CONTEXT *VmPtr,\r
985 IN UINT64 Op1,\r
986 IN UINT64 Op2\r
53c71d09 987 );\r
988\r
8e3bc754 989/**\r
990 Execute the EBC DIV instruction.\r
991\r
992 Instruction syntax:\r
993 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
994\r
995 @param VmPtr A pointer to a VM context.\r
996 @param Op1 Operand 1 from the instruction\r
997 @param Op2 Operand 2 from the instruction\r
998\r
999 @return Op1 / Op2\r
1000\r
1001**/\r
53c71d09 1002UINT64\r
1003ExecuteDIV (\r
ea7cb08c 1004 IN VM_CONTEXT *VmPtr,\r
1005 IN UINT64 Op1,\r
1006 IN UINT64 Op2\r
53c71d09 1007 );\r
1008\r
8e3bc754 1009/**\r
1010 Execute the EBC DIVU instruction\r
1011\r
1012 Instruction syntax:\r
1013 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1014\r
1015 @param VmPtr A pointer to a VM context.\r
1016 @param Op1 Operand 1 from the instruction\r
1017 @param Op2 Operand 2 from the instruction\r
1018\r
1019 @return (unsigned)Op1 / (unsigned)Op2\r
1020\r
1021**/\r
53c71d09 1022UINT64\r
1023ExecuteDIVU (\r
ea7cb08c 1024 IN VM_CONTEXT *VmPtr,\r
1025 IN UINT64 Op1,\r
1026 IN UINT64 Op2\r
53c71d09 1027 );\r
1028\r
8e3bc754 1029/**\r
1030 Execute the EBC MOD instruction.\r
1031\r
1032 Instruction syntax:\r
1033 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1034\r
1035 @param VmPtr A pointer to a VM context.\r
1036 @param Op1 Operand 1 from the instruction\r
1037 @param Op2 Operand 2 from the instruction\r
1038\r
1039 @return Op1 MODULUS Op2\r
1040\r
1041**/\r
53c71d09 1042UINT64\r
1043ExecuteMOD (\r
ea7cb08c 1044 IN VM_CONTEXT *VmPtr,\r
1045 IN UINT64 Op1,\r
1046 IN UINT64 Op2\r
53c71d09 1047 );\r
1048\r
8e3bc754 1049/**\r
1050 Execute the EBC MODU instruction.\r
1051\r
1052 Instruction syntax:\r
1053 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1054\r
1055 @param VmPtr A pointer to a VM context.\r
1056 @param Op1 Operand 1 from the instruction\r
1057 @param Op2 Operand 2 from the instruction\r
1058\r
1059 @return Op1 UNSIGNED_MODULUS Op2\r
1060\r
1061**/\r
53c71d09 1062UINT64\r
1063ExecuteMODU (\r
ea7cb08c 1064 IN VM_CONTEXT *VmPtr,\r
1065 IN UINT64 Op1,\r
1066 IN UINT64 Op2\r
53c71d09 1067 );\r
1068\r
8e3bc754 1069/**\r
1070 Execute the EBC AND instruction.\r
1071\r
1072 Instruction syntax:\r
1073 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1074\r
1075 @param VmPtr A pointer to a VM context.\r
1076 @param Op1 Operand 1 from the instruction\r
1077 @param Op2 Operand 2 from the instruction\r
1078\r
1079 @return Op1 AND Op2\r
1080\r
1081**/\r
53c71d09 1082UINT64\r
1083ExecuteAND (\r
ea7cb08c 1084 IN VM_CONTEXT *VmPtr,\r
1085 IN UINT64 Op1,\r
1086 IN UINT64 Op2\r
53c71d09 1087 );\r
1088\r
8e3bc754 1089/**\r
1090 Execute the EBC OR instruction.\r
1091\r
1092 Instruction syntax:\r
1093 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1094\r
1095 @param VmPtr A pointer to a VM context.\r
1096 @param Op1 Operand 1 from the instruction\r
1097 @param Op2 Operand 2 from the instruction\r
1098\r
1099 @return Op1 OR Op2\r
1100\r
1101**/\r
53c71d09 1102UINT64\r
1103ExecuteOR (\r
ea7cb08c 1104 IN VM_CONTEXT *VmPtr,\r
1105 IN UINT64 Op1,\r
1106 IN UINT64 Op2\r
53c71d09 1107 );\r
1108\r
8e3bc754 1109/**\r
1110 Execute the EBC XOR instruction.\r
1111\r
1112 Instruction syntax:\r
1113 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1114\r
1115 @param VmPtr A pointer to a VM context.\r
1116 @param Op1 Operand 1 from the instruction\r
1117 @param Op2 Operand 2 from the instruction\r
1118\r
1119 @return Op1 XOR Op2\r
1120\r
1121**/\r
53c71d09 1122UINT64\r
1123ExecuteXOR (\r
ea7cb08c 1124 IN VM_CONTEXT *VmPtr,\r
1125 IN UINT64 Op1,\r
1126 IN UINT64 Op2\r
53c71d09 1127 );\r
1128\r
8e3bc754 1129/**\r
1130 Execute the EBC SHL shift left instruction.\r
1131\r
1132 Instruction syntax:\r
1133 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1134\r
1135 @param VmPtr A pointer to a VM context.\r
1136 @param Op1 Operand 1 from the instruction\r
1137 @param Op2 Operand 2 from the instruction\r
1138\r
1139 @return Op1 << Op2\r
1140\r
1141**/\r
53c71d09 1142UINT64\r
1143ExecuteSHL (\r
ea7cb08c 1144 IN VM_CONTEXT *VmPtr,\r
1145 IN UINT64 Op1,\r
1146 IN UINT64 Op2\r
53c71d09 1147 );\r
1148\r
8e3bc754 1149/**\r
1150 Execute the EBC SHR instruction.\r
1151\r
1152 Instruction syntax:\r
1153 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1154\r
1155 @param VmPtr A pointer to a VM context.\r
1156 @param Op1 Operand 1 from the instruction\r
1157 @param Op2 Operand 2 from the instruction\r
1158\r
1159 @return Op1 >> Op2 (unsigned operands)\r
1160\r
1161**/\r
53c71d09 1162UINT64\r
1163ExecuteSHR (\r
ea7cb08c 1164 IN VM_CONTEXT *VmPtr,\r
1165 IN UINT64 Op1,\r
1166 IN UINT64 Op2\r
53c71d09 1167 );\r
1168\r
8e3bc754 1169/**\r
1170 Execute the EBC ASHR instruction.\r
1171\r
1172 Instruction syntax:\r
1173 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1174\r
1175 @param VmPtr A pointer to a VM context.\r
1176 @param Op1 Operand 1 from the instruction\r
1177 @param Op2 Operand 2 from the instruction\r
1178\r
1179 @return Op1 >> Op2 (signed)\r
1180\r
1181**/\r
53c71d09 1182UINT64\r
1183ExecuteASHR (\r
ea7cb08c 1184 IN VM_CONTEXT *VmPtr,\r
1185 IN UINT64 Op1,\r
1186 IN UINT64 Op2\r
53c71d09 1187 );\r
1188\r
8e3bc754 1189/**\r
1190 Execute the EBC EXTNDB instruction to sign-extend a byte value.\r
1191\r
1192 Instruction syntax:\r
1193 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1194\r
1195 @param VmPtr A pointer to a VM context.\r
1196 @param Op1 Operand 1 from the instruction\r
1197 @param Op2 Operand 2 from the instruction\r
1198\r
1199 @return (INT64)(INT8)Op2\r
1200\r
1201**/\r
53c71d09 1202UINT64\r
1203ExecuteEXTNDB (\r
ea7cb08c 1204 IN VM_CONTEXT *VmPtr,\r
1205 IN UINT64 Op1,\r
1206 IN UINT64 Op2\r
53c71d09 1207 );\r
1208\r
8e3bc754 1209/**\r
1210 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.\r
1211\r
1212 Instruction syntax:\r
1213 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1214\r
1215 @param VmPtr A pointer to a VM context.\r
1216 @param Op1 Operand 1 from the instruction\r
1217 @param Op2 Operand 2 from the instruction\r
1218\r
1219 @return (INT64)(INT16)Op2\r
1220\r
1221**/\r
53c71d09 1222UINT64\r
1223ExecuteEXTNDW (\r
ea7cb08c 1224 IN VM_CONTEXT *VmPtr,\r
1225 IN UINT64 Op1,\r
1226 IN UINT64 Op2\r
53c71d09 1227 );\r
1228\r
8e3bc754 1229/**\r
1230 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.\r
1231\r
1232 Instruction syntax:\r
1233 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
1234\r
1235 @param VmPtr A pointer to a VM context.\r
1236 @param Op1 Operand 1 from the instruction\r
1237 @param Op2 Operand 2 from the instruction\r
1238\r
1239 @return (INT64)(INT32)Op2\r
1240\r
1241**/\r
53c71d09 1242UINT64\r
1243ExecuteEXTNDD (\r
ea7cb08c 1244 IN VM_CONTEXT *VmPtr,\r
1245 IN UINT64 Op1,\r
1246 IN UINT64 Op2\r
53c71d09 1247 );\r
1248\r
1249//\r
1250// Once we retrieve the operands for the data manipulation instructions,\r
1251// call these functions to perform the operation.\r
1252//\r
34e4e297 1253CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable[] = {\r
53c71d09 1254 ExecuteNOT,\r
1255 ExecuteNEG,\r
1256 ExecuteADD,\r
1257 ExecuteSUB,\r
1258 ExecuteMUL,\r
1259 ExecuteMULU,\r
1260 ExecuteDIV,\r
1261 ExecuteDIVU,\r
1262 ExecuteMOD,\r
1263 ExecuteMODU,\r
1264 ExecuteAND,\r
1265 ExecuteOR,\r
1266 ExecuteXOR,\r
1267 ExecuteSHL,\r
1268 ExecuteSHR,\r
1269 ExecuteASHR,\r
1270 ExecuteEXTNDB,\r
1271 ExecuteEXTNDW,\r
1272 ExecuteEXTNDD,\r
1273};\r
1274\r
34e4e297 1275CONST VM_TABLE_ENTRY mVmOpcodeTable[] = {\r
53c71d09 1276 { ExecuteBREAK }, // opcode 0x00\r
1277 { ExecuteJMP }, // opcode 0x01\r
1278 { ExecuteJMP8 }, // opcode 0x02\r
1279 { ExecuteCALL }, // opcode 0x03\r
1280 { ExecuteRET }, // opcode 0x04\r
1281 { ExecuteCMP }, // opcode 0x05 CMPeq\r
1282 { ExecuteCMP }, // opcode 0x06 CMPlte\r
1283 { ExecuteCMP }, // opcode 0x07 CMPgte\r
1284 { ExecuteCMP }, // opcode 0x08 CMPulte\r
1285 { ExecuteCMP }, // opcode 0x09 CMPugte\r
1286 { ExecuteUnsignedDataManip }, // opcode 0x0A NOT\r
1287 { ExecuteSignedDataManip }, // opcode 0x0B NEG\r
1288 { ExecuteSignedDataManip }, // opcode 0x0C ADD\r
1289 { ExecuteSignedDataManip }, // opcode 0x0D SUB\r
1290 { ExecuteSignedDataManip }, // opcode 0x0E MUL\r
1291 { ExecuteUnsignedDataManip }, // opcode 0x0F MULU\r
1292 { ExecuteSignedDataManip }, // opcode 0x10 DIV\r
1293 { ExecuteUnsignedDataManip }, // opcode 0x11 DIVU\r
1294 { ExecuteSignedDataManip }, // opcode 0x12 MOD\r
1295 { ExecuteUnsignedDataManip }, // opcode 0x13 MODU\r
1296 { ExecuteUnsignedDataManip }, // opcode 0x14 AND\r
1297 { ExecuteUnsignedDataManip }, // opcode 0x15 OR\r
1298 { ExecuteUnsignedDataManip }, // opcode 0x16 XOR\r
1299 { ExecuteUnsignedDataManip }, // opcode 0x17 SHL\r
1300 { ExecuteUnsignedDataManip }, // opcode 0x18 SHR\r
1301 { ExecuteSignedDataManip }, // opcode 0x19 ASHR\r
1302 { ExecuteUnsignedDataManip }, // opcode 0x1A EXTNDB\r
1303 { ExecuteUnsignedDataManip }, // opcode 0x1B EXTNDW\r
1304 { ExecuteUnsignedDataManip }, // opcode 0x1C EXTNDD\r
1305 { ExecuteMOVxx }, // opcode 0x1D MOVBW\r
1306 { ExecuteMOVxx }, // opcode 0x1E MOVWW\r
1307 { ExecuteMOVxx }, // opcode 0x1F MOVDW\r
1308 { ExecuteMOVxx }, // opcode 0x20 MOVQW\r
1309 { ExecuteMOVxx }, // opcode 0x21 MOVBD\r
1310 { ExecuteMOVxx }, // opcode 0x22 MOVWD\r
1311 { ExecuteMOVxx }, // opcode 0x23 MOVDD\r
1312 { ExecuteMOVxx }, // opcode 0x24 MOVQD\r
1313 { ExecuteMOVsnw }, // opcode 0x25 MOVsnw\r
1314 { ExecuteMOVsnd }, // opcode 0x26 MOVsnd\r
1315 { NULL }, // opcode 0x27\r
1316 { ExecuteMOVxx }, // opcode 0x28 MOVqq\r
1317 { ExecuteLOADSP }, // opcode 0x29 LOADSP SP1, R2\r
1318 { ExecuteSTORESP }, // opcode 0x2A STORESP R1, SP2\r
1319 { ExecutePUSH }, // opcode 0x2B PUSH {@}R1 [imm16]\r
1320 { ExecutePOP }, // opcode 0x2C POP {@}R1 [imm16]\r
1321 { ExecuteCMPI }, // opcode 0x2D CMPIEQ\r
1322 { ExecuteCMPI }, // opcode 0x2E CMPILTE\r
1323 { ExecuteCMPI }, // opcode 0x2F CMPIGTE\r
1324 { ExecuteCMPI }, // opcode 0x30 CMPIULTE\r
1325 { ExecuteCMPI }, // opcode 0x31 CMPIUGTE\r
1326 { ExecuteMOVxx }, // opcode 0x32 MOVN\r
1327 { ExecuteMOVxx }, // opcode 0x33 MOVND\r
1328 { NULL }, // opcode 0x34\r
1329 { ExecutePUSHn }, // opcode 0x35\r
1330 { ExecutePOPn }, // opcode 0x36\r
1331 { ExecuteMOVI }, // opcode 0x37 - mov immediate data\r
1332 { ExecuteMOVIn }, // opcode 0x38 - mov immediate natural\r
ead7e7dc 1333 { ExecuteMOVREL }, // opcode 0x39 - move data relative to PC\r
1334 { NULL }, // opcode 0x3a\r
1335 { NULL }, // opcode 0x3b \r
1336 { NULL }, // opcode 0x3c \r
1337 { NULL }, // opcode 0x3d \r
1338 { NULL }, // opcode 0x3e \r
1339 { NULL } // opcode 0x3f \r
53c71d09 1340};\r
1341\r
1342//\r
1343// Length of JMP instructions, depending on upper two bits of opcode.\r
1344//\r
34e4e297 1345CONST UINT8 mJMPLen[] = { 2, 2, 6, 10 };\r
53c71d09 1346\r
fb0b259e 1347/**\r
53c71d09 1348 Given a pointer to a new VM context, execute one or more instructions. This\r
1349 function is only used for test purposes via the EBC VM test protocol.\r
1350\r
8e3bc754 1351 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.\r
1352 @param VmPtr A pointer to a VM context.\r
1353 @param InstructionCount A pointer to a UINTN value holding the number of\r
1354 instructions to execute. If it holds value of 0,\r
1355 then the instruction to be executed is 1.\r
53c71d09 1356\r
8e3bc754 1357 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.\r
1358 @retval EFI_SUCCESS All of the instructions are executed successfully.\r
53c71d09 1359\r
fb0b259e 1360**/\r
1361EFI_STATUS\r
c8ad2d7a 1362EFIAPI\r
fb0b259e 1363EbcExecuteInstructions (\r
1364 IN EFI_EBC_VM_TEST_PROTOCOL *This,\r
1365 IN VM_CONTEXT *VmPtr,\r
1366 IN OUT UINTN *InstructionCount\r
1367 )\r
53c71d09 1368{\r
1369 UINTN ExecFunc;\r
1370 EFI_STATUS Status;\r
1371 UINTN InstructionsLeft;\r
1372 UINTN SavedInstructionCount;\r
1373\r
1374 Status = EFI_SUCCESS;\r
1375\r
1376 if (*InstructionCount == 0) {\r
1377 InstructionsLeft = 1;\r
1378 } else {\r
1379 InstructionsLeft = *InstructionCount;\r
1380 }\r
1381\r
1382 SavedInstructionCount = *InstructionCount;\r
1383 *InstructionCount = 0;\r
1384\r
1385 //\r
1386 // Index into the opcode table using the opcode byte for this instruction.\r
1387 // This gives you the execute function, which we first test for null, then\r
1388 // call it if it's not null.\r
1389 //\r
1390 while (InstructionsLeft != 0) {\r
ead7e7dc 1391 ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;\r
53c71d09 1392 if (ExecFunc == (UINTN) NULL) {\r
1393 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);\r
1394 return EFI_UNSUPPORTED;\r
1395 } else {\r
ead7e7dc 1396 mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);\r
53c71d09 1397 *InstructionCount = *InstructionCount + 1;\r
1398 }\r
1399\r
1400 //\r
1401 // Decrement counter if applicable\r
1402 //\r
1403 if (SavedInstructionCount != 0) {\r
1404 InstructionsLeft--;\r
1405 }\r
1406 }\r
1407\r
1408 return Status;\r
1409}\r
1410\r
53c71d09 1411\r
fb0b259e 1412/**\r
53c71d09 1413 Execute an EBC image from an entry point or from a published protocol.\r
1414\r
8e3bc754 1415 @param VmPtr A pointer to a VM context.\r
53c71d09 1416\r
8e3bc754 1417 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.\r
1418 @retval EFI_SUCCESS All of the instructions are executed successfully.\r
53c71d09 1419\r
fb0b259e 1420**/\r
1421EFI_STATUS\r
1422EbcExecute (\r
1423 IN VM_CONTEXT *VmPtr\r
1424 )\r
53c71d09 1425{\r
1426 UINTN ExecFunc;\r
1427 UINT8 StackCorrupted;\r
1428 EFI_STATUS Status;\r
1429 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *EbcSimpleDebugger;\r
1430\r
1431 mVmPtr = VmPtr;\r
1432 EbcSimpleDebugger = NULL;\r
1433 Status = EFI_SUCCESS;\r
1434 StackCorrupted = 0;\r
1435\r
1436 //\r
1437 // Make sure the magic value has been put on the stack before we got here.\r
1438 //\r
1439 if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {\r
1440 StackCorrupted = 1;\r
1441 }\r
1442\r
1ccdbf2a 1443 VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->Gpr[0] + 8);\r
53c71d09 1444\r
1445 //\r
1446 // Try to get the debug support for EBC\r
1447 //\r
1448 DEBUG_CODE_BEGIN ();\r
1449 Status = gBS->LocateProtocol (\r
c8ad2d7a 1450 &gEfiEbcSimpleDebuggerProtocolGuid,\r
53c71d09 1451 NULL,\r
1452 (VOID **) &EbcSimpleDebugger\r
1453 );\r
1454 if (EFI_ERROR (Status)) {\r
1455 EbcSimpleDebugger = NULL;\r
1456 }\r
1457 DEBUG_CODE_END ();\r
1458\r
1459 //\r
1460 // Save the start IP for debug. For example, if we take an exception we\r
1461 // can print out the location of the exception relative to the entry point,\r
1462 // which could then be used in a disassembly listing to find the problem.\r
1463 //\r
1464 VmPtr->EntryPoint = (VOID *) VmPtr->Ip;\r
1465\r
1466 //\r
1467 // We'll wait for this flag to know when we're done. The RET\r
1468 // instruction sets it if it runs out of stack.\r
1469 //\r
1470 VmPtr->StopFlags = 0;\r
366219ab 1471 while ((VmPtr->StopFlags & STOPFLAG_APP_DONE) == 0) {\r
53c71d09 1472 //\r
1473 // If we've found a simple debugger protocol, call it\r
1474 //\r
1475 DEBUG_CODE_BEGIN ();\r
1476 if (EbcSimpleDebugger != NULL) {\r
1477 EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);\r
1478 }\r
1479 DEBUG_CODE_END ();\r
1480\r
53c71d09 1481 //\r
1482 // Use the opcode bits to index into the opcode dispatch table. If the\r
1483 // function pointer is null then generate an exception.\r
1484 //\r
1485 ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;\r
1486 if (ExecFunc == (UINTN) NULL) {\r
1487 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);\r
1488 Status = EFI_UNSUPPORTED;\r
1489 goto Done;\r
1490 }\r
1491 //\r
1492 // The EBC VM is a strongly ordered processor, so perform a fence operation before\r
1493 // and after each instruction is executed.\r
1494 //\r
1495 MemoryFence ();\r
1496\r
1497 mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);\r
1498\r
1499 MemoryFence ();\r
1500\r
1501 //\r
1502 // If the step flag is set, signal an exception and continue. We don't\r
1503 // clear it here. Assuming the debugger is responsible for clearing it.\r
1504 //\r
1505 if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {\r
1506 EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);\r
1507 }\r
1508 //\r
1509 // Make sure stack has not been corrupted. Only report it once though.\r
1510 //\r
366219ab 1511 if ((StackCorrupted == 0) && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {\r
53c71d09 1512 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);\r
1513 StackCorrupted = 1;\r
1514 }\r
1ccdbf2a 1515 if ((StackCorrupted == 0) && ((UINT64)VmPtr->Gpr[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {\r
53c71d09 1516 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);\r
1517 StackCorrupted = 1;\r
1518 }\r
1519 }\r
1520\r
1521Done:\r
1522 mVmPtr = NULL;\r
1523\r
1524 return Status;\r
1525}\r
1526\r
53c71d09 1527\r
fb0b259e 1528/**\r
53c71d09 1529 Execute the MOVxx instructions.\r
1530\r
8e3bc754 1531 Instruction format:\r
34e4e297 1532\r
8e3bc754 1533 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}\r
1534 MOVqq {@}R1 {Index64}, {@}R2 {Index64}\r
34e4e297 1535\r
8e3bc754 1536 Copies contents of [R2] -> [R1], zero extending where required.\r
34e4e297 1537\r
8e3bc754 1538 First character indicates the size of the move.\r
1539 Second character indicates the size of the index(s).\r
34e4e297 1540\r
8e3bc754 1541 Invalid to have R1 direct with index.\r
1542\r
1543 @param VmPtr A pointer to a VM context.\r
1544\r
1545 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
1546 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 1547\r
fb0b259e 1548**/\r
fb0b259e 1549EFI_STATUS\r
1550ExecuteMOVxx (\r
1551 IN VM_CONTEXT *VmPtr\r
1552 )\r
53c71d09 1553{\r
1554 UINT8 Opcode;\r
1555 UINT8 OpcMasked;\r
1556 UINT8 Operands;\r
1557 UINT8 Size;\r
1558 UINT8 MoveSize;\r
1559 INT16 Index16;\r
1560 INT32 Index32;\r
1561 INT64 Index64Op1;\r
1562 INT64 Index64Op2;\r
1563 UINT64 Data64;\r
1564 UINT64 DataMask;\r
1565 UINTN Source;\r
1566\r
1567 Opcode = GETOPCODE (VmPtr);\r
1568 OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);\r
1569\r
1570 //\r
1571 // Get the operands byte so we can get R1 and R2\r
1572 //\r
1573 Operands = GETOPERANDS (VmPtr);\r
1574\r
1575 //\r
1576 // Assume no indexes\r
1577 //\r
1578 Index64Op1 = 0;\r
1579 Index64Op2 = 0;\r
1580 Data64 = 0;\r
1581\r
1582 //\r
1583 // Determine if we have an index/immediate data. Base instruction size\r
1584 // is 2 (opcode + operands). Add to this size each index specified.\r
1585 //\r
1586 Size = 2;\r
366219ab 1587 if ((Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {\r
53c71d09 1588 //\r
1589 // Determine size of the index from the opcode. Then get it.\r
1590 //\r
1591 if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {\r
1592 //\r
1593 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.\r
1594 // Get one or both index values.\r
1595 //\r
366219ab 1596 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {\r
53c71d09 1597 Index16 = VmReadIndex16 (VmPtr, 2);\r
1598 Index64Op1 = (INT64) Index16;\r
1599 Size += sizeof (UINT16);\r
1600 }\r
1601\r
366219ab 1602 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 1603 Index16 = VmReadIndex16 (VmPtr, Size);\r
1604 Index64Op2 = (INT64) Index16;\r
1605 Size += sizeof (UINT16);\r
1606 }\r
1607 } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {\r
1608 //\r
1609 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index\r
1610 //\r
366219ab 1611 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {\r
53c71d09 1612 Index32 = VmReadIndex32 (VmPtr, 2);\r
1613 Index64Op1 = (INT64) Index32;\r
1614 Size += sizeof (UINT32);\r
1615 }\r
1616\r
366219ab 1617 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 1618 Index32 = VmReadIndex32 (VmPtr, Size);\r
1619 Index64Op2 = (INT64) Index32;\r
1620 Size += sizeof (UINT32);\r
1621 }\r
1622 } else if (OpcMasked == OPCODE_MOVQQ) {\r
1623 //\r
1624 // MOVqq -- only form with a 64-bit index\r
1625 //\r
366219ab 1626 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {\r
53c71d09 1627 Index64Op1 = VmReadIndex64 (VmPtr, 2);\r
1628 Size += sizeof (UINT64);\r
1629 }\r
1630\r
366219ab 1631 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 1632 Index64Op2 = VmReadIndex64 (VmPtr, Size);\r
1633 Size += sizeof (UINT64);\r
1634 }\r
1635 } else {\r
1636 //\r
1637 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index\r
1638 //\r
1639 EbcDebugSignalException (\r
1640 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1641 EXCEPTION_FLAG_FATAL,\r
1642 VmPtr\r
1643 );\r
1644 return EFI_UNSUPPORTED;\r
1645 }\r
1646 }\r
1647 //\r
1648 // Determine the size of the move, and create a mask for it so we can\r
1649 // clear unused bits.\r
1650 //\r
1651 if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {\r
1652 MoveSize = DATA_SIZE_8;\r
1653 DataMask = 0xFF;\r
1654 } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {\r
1655 MoveSize = DATA_SIZE_16;\r
1656 DataMask = 0xFFFF;\r
1657 } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {\r
1658 MoveSize = DATA_SIZE_32;\r
1659 DataMask = 0xFFFFFFFF;\r
1660 } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {\r
1661 MoveSize = DATA_SIZE_64;\r
1662 DataMask = (UINT64)~0;\r
1663 } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {\r
1664 MoveSize = DATA_SIZE_N;\r
1665 DataMask = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));\r
1666 } else {\r
1667 //\r
1668 // We were dispatched to this function and we don't recognize the opcode\r
1669 //\r
1670 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);\r
1671 return EFI_UNSUPPORTED;\r
1672 }\r
1673 //\r
1674 // Now get the source address\r
1675 //\r
1676 if (OPERAND2_INDIRECT (Operands)) {\r
1677 //\r
1678 // Indirect form @R2. Compute address of operand2\r
1679 //\r
1ccdbf2a 1680 Source = (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);\r
53c71d09 1681 //\r
1682 // Now get the data from the source. Always 0-extend and let the compiler\r
1683 // sign-extend where required.\r
1684 //\r
1685 switch (MoveSize) {\r
1686 case DATA_SIZE_8:\r
1687 Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);\r
1688 break;\r
1689\r
1690 case DATA_SIZE_16:\r
1691 Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);\r
1692 break;\r
1693\r
1694 case DATA_SIZE_32:\r
1695 Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);\r
1696 break;\r
1697\r
1698 case DATA_SIZE_64:\r
1699 Data64 = (UINT64) VmReadMem64 (VmPtr, Source);\r
1700 break;\r
1701\r
1702 case DATA_SIZE_N:\r
1703 Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);\r
1704 break;\r
1705\r
1706 default:\r
1707 //\r
1708 // not reached\r
1709 //\r
1710 break;\r
1711 }\r
1712 } else {\r
1713 //\r
1714 // Not indirect source: MOVxx {@}Rx, Ry [Index]\r
1715 //\r
c9325700 1716 Data64 = (UINT64) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);\r
53c71d09 1717 //\r
1718 // Did Operand2 have an index? If so, treat as two signed values since\r
1719 // indexes are signed values.\r
1720 //\r
366219ab 1721 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 1722 //\r
1723 // NOTE: need to find a way to fix this, most likely by changing the VM\r
1724 // implementation to remove the stack gap. To do that, we'd need to\r
1725 // allocate stack space for the VM and actually set the system\r
1726 // stack pointer to the allocated buffer when the VM starts.\r
1727 //\r
1728 // Special case -- if someone took the address of a function parameter\r
1729 // then we need to make sure it's not in the stack gap. We can identify\r
1730 // this situation if (Operand2 register == 0) && (Operand2 is direct)\r
1731 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)\r
1732 // Situations that to be aware of:\r
1733 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize\r
1734 //\r
1735 if ((OPERAND2_REGNUM (Operands) == 0) &&\r
1736 (!OPERAND2_INDIRECT (Operands)) &&\r
1737 (Index64Op2 > 0) &&\r
1738 (OPERAND1_REGNUM (Operands) == 0) &&\r
1739 (OPERAND1_INDIRECT (Operands))\r
1740 ) {\r
1741 Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);\r
1742 }\r
1743 }\r
1744 }\r
1745 //\r
1746 // Now write it back\r
1747 //\r
1748 if (OPERAND1_INDIRECT (Operands)) {\r
1749 //\r
1750 // Reuse the Source variable to now be dest.\r
1751 //\r
1ccdbf2a 1752 Source = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index64Op1);\r
53c71d09 1753 //\r
1754 // Do the write based on the size\r
1755 //\r
1756 switch (MoveSize) {\r
1757 case DATA_SIZE_8:\r
1758 VmWriteMem8 (VmPtr, Source, (UINT8) Data64);\r
1759 break;\r
1760\r
1761 case DATA_SIZE_16:\r
1762 VmWriteMem16 (VmPtr, Source, (UINT16) Data64);\r
1763 break;\r
1764\r
1765 case DATA_SIZE_32:\r
1766 VmWriteMem32 (VmPtr, Source, (UINT32) Data64);\r
1767 break;\r
1768\r
1769 case DATA_SIZE_64:\r
1770 VmWriteMem64 (VmPtr, Source, Data64);\r
1771 break;\r
1772\r
1773 case DATA_SIZE_N:\r
1774 VmWriteMemN (VmPtr, Source, (UINTN) Data64);\r
1775 break;\r
1776\r
1777 default:\r
1778 //\r
1779 // not reached\r
1780 //\r
1781 break;\r
1782 }\r
1783 } else {\r
1784 //\r
1785 // Operand1 direct.\r
1786 // Make sure we didn't have an index on operand1.\r
1787 //\r
366219ab 1788 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {\r
53c71d09 1789 EbcDebugSignalException (\r
1790 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1791 EXCEPTION_FLAG_FATAL,\r
1792 VmPtr\r
1793 );\r
1794 return EFI_UNSUPPORTED;\r
1795 }\r
1796 //\r
1797 // Direct storage in register. Clear unused bits and store back to\r
1798 // register.\r
1799 //\r
1ccdbf2a 1800 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;\r
53c71d09 1801 }\r
1802 //\r
1803 // Advance the instruction pointer\r
1804 //\r
1805 VmPtr->Ip += Size;\r
1806 return EFI_SUCCESS;\r
1807}\r
1808\r
53c71d09 1809\r
fb0b259e 1810/**\r
8e3bc754 1811 Execute the EBC BREAK instruction.\r
53c71d09 1812\r
8e3bc754 1813 @param VmPtr A pointer to a VM context.\r
53c71d09 1814\r
8e3bc754 1815 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 1816\r
fb0b259e 1817**/\r
fb0b259e 1818EFI_STATUS\r
1819ExecuteBREAK (\r
1820 IN VM_CONTEXT *VmPtr\r
1821 )\r
53c71d09 1822{\r
e618d0cb 1823 EFI_STATUS Status;\r
53c71d09 1824 UINT8 Operands;\r
1825 VOID *EbcEntryPoint;\r
1826 VOID *Thunk;\r
1827 UINT64 U64EbcEntryPoint;\r
1828 INT32 Offset;\r
1829\r
4e1005ec 1830 Thunk = NULL;\r
53c71d09 1831 Operands = GETOPERANDS (VmPtr);\r
1832 switch (Operands) {\r
1833 //\r
1834 // Runaway program break. Generate an exception and terminate\r
1835 //\r
1836 case 0:\r
1837 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);\r
1838 break;\r
1839\r
1840 //\r
1841 // Get VM version -- return VM revision number in R7\r
1842 //\r
1843 case 1:\r
1844 //\r
1845 // Bits:\r
1846 // 63-17 = 0\r
1847 // 16-8 = Major version\r
1848 // 7-0 = Minor version\r
1849 //\r
1ccdbf2a 1850 VmPtr->Gpr[7] = GetVmVersion ();\r
53c71d09 1851 break;\r
1852\r
1853 //\r
1854 // Debugger breakpoint\r
1855 //\r
1856 case 3:\r
1857 VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;\r
1858 //\r
1859 // See if someone has registered a handler\r
1860 //\r
1861 EbcDebugSignalException (\r
1862 EXCEPT_EBC_BREAKPOINT,\r
1863 EXCEPTION_FLAG_NONE,\r
1864 VmPtr\r
1865 );\r
1866 break;\r
1867\r
1868 //\r
1869 // System call, which there are none, so NOP it.\r
1870 //\r
1871 case 4:\r
1872 break;\r
1873\r
1874 //\r
1875 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)\r
1876 // "offset from self" pointer to the EBC entry point.\r
1877 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.\r
1878 //\r
1879 case 5:\r
1ccdbf2a 1880 Offset = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7]);\r
1881 U64EbcEntryPoint = (UINT64) (VmPtr->Gpr[7] + Offset + 4);\r
53c71d09 1882 EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint;\r
1883\r
1884 //\r
1885 // Now create a new thunk\r
1886 //\r
e618d0cb 1887 Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);\r
1888 if (EFI_ERROR (Status)) {\r
1889 return Status;\r
1890 }\r
53c71d09 1891\r
1892 //\r
1893 // Finally replace the EBC entry point memory with the thunk address\r
1894 //\r
1ccdbf2a 1895 VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[7], (UINT64) (UINTN) Thunk);\r
53c71d09 1896 break;\r
1897\r
1898 //\r
1899 // Compiler setting version per value in R7\r
1900 //\r
1901 case 6:\r
1ccdbf2a 1902 VmPtr->CompilerVersion = (UINT32) VmPtr->Gpr[7];\r
53c71d09 1903 //\r
1904 // Check compiler version against VM version?\r
1905 //\r
1906 break;\r
1907\r
1908 //\r
1909 // Unhandled break code. Signal exception.\r
1910 //\r
1911 default:\r
1912 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);\r
1913 break;\r
1914 }\r
1915 //\r
1916 // Advance IP\r
1917 //\r
1918 VmPtr->Ip += 2;\r
1919 return EFI_SUCCESS;\r
1920}\r
1921\r
fb0b259e 1922\r
1923/**\r
8e3bc754 1924 Execute the JMP instruction.\r
1925\r
1926 Instruction syntax:\r
1927 JMP64{cs|cc} Immed64\r
1928 JMP32{cs|cc} {@}R1 {Immed32|Index32}\r
34e4e297 1929\r
8e3bc754 1930 Encoding:\r
1931 b0.7 - immediate data present\r
1932 b0.6 - 1 = 64 bit immediate data\r
1933 0 = 32 bit immediate data\r
1934 b1.7 - 1 = conditional\r
1935 b1.6 1 = CS (condition set)\r
1936 0 = CC (condition clear)\r
1937 b1.4 1 = relative address\r
1938 0 = absolute address\r
1939 b1.3 1 = operand1 indirect\r
1940 b1.2-0 operand 1\r
1941\r
1942 @param VmPtr A pointer to a VM context.\r
1943\r
1944 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
1945 @retval EFI_SUCCESS The instruction is executed successfully.\r
fb0b259e 1946\r
1947**/\r
53c71d09 1948EFI_STATUS\r
1949ExecuteJMP (\r
1950 IN VM_CONTEXT *VmPtr\r
1951 )\r
53c71d09 1952{\r
1953 UINT8 Opcode;\r
1954 UINT8 CompareSet;\r
1955 UINT8 ConditionFlag;\r
1956 UINT8 Size;\r
1957 UINT8 Operand;\r
1958 UINT64 Data64;\r
1959 INT32 Index32;\r
1960 UINTN Addr;\r
1961\r
1962 Operand = GETOPERANDS (VmPtr);\r
1963 Opcode = GETOPCODE (VmPtr);\r
1964\r
1965 //\r
1966 // Get instruction length from the opcode. The upper two bits are used here\r
1967 // to index into the length array.\r
1968 //\r
1969 Size = mJMPLen[(Opcode >> 6) & 0x03];\r
1970\r
1971 //\r
1972 // Decode instruction conditions\r
1973 // If we haven't met the condition, then simply advance the IP and return.\r
1974 //\r
366219ab 1975 CompareSet = (UINT8) (((Operand & JMP_M_CS) != 0) ? 1 : 0);\r
53c71d09 1976 ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);\r
366219ab 1977 if ((Operand & CONDITION_M_CONDITIONAL) != 0) {\r
53c71d09 1978 if (CompareSet != ConditionFlag) {\r
1979 VmPtr->Ip += Size;\r
1980 return EFI_SUCCESS;\r
1981 }\r
1982 }\r
1983 //\r
1984 // Check for 64-bit form and do it right away since it's the most\r
1985 // straight-forward form.\r
1986 //\r
366219ab 1987 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {\r
53c71d09 1988 //\r
1989 // Double check for immediate-data, which is required. If not there,\r
1990 // then signal an exception\r
1991 //\r
366219ab 1992 if ((Opcode & OPCODE_M_IMMDATA) == 0) {\r
53c71d09 1993 EbcDebugSignalException (\r
1994 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1995 EXCEPTION_FLAG_ERROR,\r
1996 VmPtr\r
1997 );\r
1998 return EFI_UNSUPPORTED;\r
1999 }\r
2000 //\r
2001 // 64-bit immediate data is full address. Read the immediate data,\r
2002 // check for alignment, and jump absolute.\r
2003 //\r
c9325700 2004 Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);\r
53c71d09 2005 if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {\r
2006 EbcDebugSignalException (\r
2007 EXCEPT_EBC_ALIGNMENT_CHECK,\r
2008 EXCEPTION_FLAG_FATAL,\r
2009 VmPtr\r
2010 );\r
2011\r
2012 return EFI_UNSUPPORTED;\r
2013 }\r
2014\r
2015 //\r
2016 // Take jump -- relative or absolute\r
2017 //\r
366219ab 2018 if ((Operand & JMP_M_RELATIVE) != 0) {\r
53c71d09 2019 VmPtr->Ip += (UINTN) Data64 + Size;\r
2020 } else {\r
2021 VmPtr->Ip = (VMIP) (UINTN) Data64;\r
2022 }\r
2023\r
2024 return EFI_SUCCESS;\r
2025 }\r
2026 //\r
2027 // 32-bit forms:\r
2028 // Get the index if there is one. May be either an index, or an immediate\r
2029 // offset depending on indirect operand.\r
2030 // JMP32 @R1 Index32 -- immediate data is an index\r
2031 // JMP32 R1 Immed32 -- immedate data is an offset\r
2032 //\r
366219ab 2033 if ((Opcode & OPCODE_M_IMMDATA) != 0) {\r
53c71d09 2034 if (OPERAND1_INDIRECT (Operand)) {\r
2035 Index32 = VmReadIndex32 (VmPtr, 2);\r
2036 } else {\r
2037 Index32 = VmReadImmed32 (VmPtr, 2);\r
2038 }\r
2039 } else {\r
2040 Index32 = 0;\r
2041 }\r
2042 //\r
2043 // Get the register data. If R == 0, then special case where it's ignored.\r
2044 //\r
2045 if (OPERAND1_REGNUM (Operand) == 0) {\r
2046 Data64 = 0;\r
2047 } else {\r
c9325700 2048 Data64 = (UINT64) OPERAND1_REGDATA (VmPtr, Operand);\r
53c71d09 2049 }\r
2050 //\r
2051 // Decode the forms\r
2052 //\r
2053 if (OPERAND1_INDIRECT (Operand)) {\r
2054 //\r
2055 // Form: JMP32 @Rx {Index32}\r
2056 //\r
2057 Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);\r
2058 if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {\r
2059 EbcDebugSignalException (\r
2060 EXCEPT_EBC_ALIGNMENT_CHECK,\r
2061 EXCEPTION_FLAG_FATAL,\r
2062 VmPtr\r
2063 );\r
2064\r
2065 return EFI_UNSUPPORTED;\r
2066 }\r
2067\r
366219ab 2068 if ((Operand & JMP_M_RELATIVE) != 0) {\r
53c71d09 2069 VmPtr->Ip += (UINTN) Addr + Size;\r
2070 } else {\r
2071 VmPtr->Ip = (VMIP) Addr;\r
2072 }\r
2073 } else {\r
2074 //\r
2075 // Form: JMP32 Rx {Immed32}\r
2076 //\r
2077 Addr = (UINTN) (Data64 + Index32);\r
2078 if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {\r
2079 EbcDebugSignalException (\r
2080 EXCEPT_EBC_ALIGNMENT_CHECK,\r
2081 EXCEPTION_FLAG_FATAL,\r
2082 VmPtr\r
2083 );\r
2084\r
2085 return EFI_UNSUPPORTED;\r
2086 }\r
2087\r
366219ab 2088 if ((Operand & JMP_M_RELATIVE) != 0) {\r
53c71d09 2089 VmPtr->Ip += (UINTN) Addr + Size;\r
2090 } else {\r
2091 VmPtr->Ip = (VMIP) Addr;\r
2092 }\r
2093 }\r
2094\r
2095 return EFI_SUCCESS;\r
2096}\r
2097\r
53c71d09 2098\r
fb0b259e 2099/**\r
8e3bc754 2100 Execute the EBC JMP8 instruction.\r
53c71d09 2101\r
8e3bc754 2102 Instruction syntax:\r
2103 JMP8{cs|cc} Offset/2\r
53c71d09 2104\r
8e3bc754 2105 @param VmPtr A pointer to a VM context.\r
2106\r
2107 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2108\r
fb0b259e 2109**/\r
fb0b259e 2110EFI_STATUS\r
2111ExecuteJMP8 (\r
2112 IN VM_CONTEXT *VmPtr\r
2113 )\r
53c71d09 2114{\r
2115 UINT8 Opcode;\r
2116 UINT8 ConditionFlag;\r
2117 UINT8 CompareSet;\r
2118 INT8 Offset;\r
2119\r
2120 //\r
2121 // Decode instruction.\r
2122 //\r
2123 Opcode = GETOPCODE (VmPtr);\r
366219ab 2124 CompareSet = (UINT8) (((Opcode & JMP_M_CS) != 0) ? 1 : 0);\r
53c71d09 2125 ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);\r
2126\r
2127 //\r
2128 // If we haven't met the condition, then simply advance the IP and return\r
2129 //\r
366219ab 2130 if ((Opcode & CONDITION_M_CONDITIONAL) != 0) {\r
53c71d09 2131 if (CompareSet != ConditionFlag) {\r
2132 VmPtr->Ip += 2;\r
2133 return EFI_SUCCESS;\r
2134 }\r
2135 }\r
2136 //\r
2137 // Get the offset from the instruction stream. It's relative to the\r
2138 // following instruction, and divided by 2.\r
2139 //\r
2140 Offset = VmReadImmed8 (VmPtr, 1);\r
2141 //\r
2142 // Want to check for offset == -2 and then raise an exception?\r
2143 //\r
2144 VmPtr->Ip += (Offset * 2) + 2;\r
2145 return EFI_SUCCESS;\r
2146}\r
2147\r
fb0b259e 2148\r
2149/**\r
8e3bc754 2150 Execute the EBC MOVI.\r
2151\r
2152 Instruction syntax:\r
34e4e297 2153\r
8e3bc754 2154 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
34e4e297 2155\r
8e3bc754 2156 First variable character specifies the move size\r
2157 Second variable character specifies size of the immediate data\r
34e4e297 2158\r
8e3bc754 2159 Sign-extend the immediate data to the size of the operation, and zero-extend\r
2160 if storing to a register.\r
34e4e297 2161\r
8e3bc754 2162 Operand1 direct with index/immed is invalid.\r
fb0b259e 2163\r
8e3bc754 2164 @param VmPtr A pointer to a VM context.\r
fb0b259e 2165\r
34e4e297 2166 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 2167 @retval EFI_SUCCESS The instruction is executed successfully.\r
fb0b259e 2168\r
2169**/\r
53c71d09 2170EFI_STATUS\r
2171ExecuteMOVI (\r
2172 IN VM_CONTEXT *VmPtr\r
2173 )\r
53c71d09 2174{\r
2175 UINT8 Opcode;\r
2176 UINT8 Operands;\r
2177 UINT8 Size;\r
2178 INT16 Index16;\r
2179 INT64 ImmData64;\r
2180 UINT64 Op1;\r
2181 UINT64 Mask64;\r
2182\r
2183 //\r
2184 // Get the opcode and operands byte so we can get R1 and R2\r
2185 //\r
2186 Opcode = GETOPCODE (VmPtr);\r
2187 Operands = GETOPERANDS (VmPtr);\r
2188\r
2189 //\r
2190 // Get the index (16-bit) if present\r
2191 //\r
366219ab 2192 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2193 Index16 = VmReadIndex16 (VmPtr, 2);\r
2194 Size = 4;\r
2195 } else {\r
2196 Index16 = 0;\r
2197 Size = 2;\r
2198 }\r
2199 //\r
2200 // Extract the immediate data. Sign-extend always.\r
2201 //\r
2202 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
2203 ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);\r
2204 Size += 2;\r
2205 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
2206 ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);\r
2207 Size += 4;\r
2208 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
2209 ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);\r
2210 Size += 8;\r
2211 } else {\r
2212 //\r
2213 // Invalid encoding\r
2214 //\r
2215 EbcDebugSignalException (\r
2216 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2217 EXCEPTION_FLAG_FATAL,\r
2218 VmPtr\r
2219 );\r
2220 return EFI_UNSUPPORTED;\r
2221 }\r
2222 //\r
2223 // Now write back the result\r
2224 //\r
2225 if (!OPERAND1_INDIRECT (Operands)) {\r
2226 //\r
2227 // Operand1 direct. Make sure it didn't have an index.\r
2228 //\r
366219ab 2229 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2230 EbcDebugSignalException (\r
2231 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2232 EXCEPTION_FLAG_FATAL,\r
2233 VmPtr\r
2234 );\r
2235 return EFI_UNSUPPORTED;\r
2236 }\r
2237 //\r
2238 // Writing directly to a register. Clear unused bits.\r
2239 //\r
2240 if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {\r
2241 Mask64 = 0x000000FF;\r
2242 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {\r
2243 Mask64 = 0x0000FFFF;\r
2244 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {\r
2245 Mask64 = 0x00000000FFFFFFFF;\r
2246 } else {\r
2247 Mask64 = (UINT64)~0;\r
2248 }\r
2249\r
1ccdbf2a 2250 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;\r
53c71d09 2251 } else {\r
2252 //\r
2253 // Get the address then write back based on size of the move\r
2254 //\r
1ccdbf2a 2255 Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;\r
53c71d09 2256 if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {\r
2257 VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);\r
2258 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {\r
2259 VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);\r
2260 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {\r
2261 VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);\r
2262 } else {\r
c9325700 2263 VmWriteMem64 (VmPtr, (UINTN) Op1, (UINT64) ImmData64);\r
53c71d09 2264 }\r
2265 }\r
2266 //\r
2267 // Advance the instruction pointer\r
2268 //\r
2269 VmPtr->Ip += Size;\r
2270 return EFI_SUCCESS;\r
2271}\r
2272\r
53c71d09 2273\r
fb0b259e 2274/**\r
53c71d09 2275 Execute the EBC MOV immediate natural. This instruction moves an immediate\r
2276 index value into a register or memory location.\r
2277\r
8e3bc754 2278 Instruction syntax:\r
34e4e297 2279\r
8e3bc754 2280 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64\r
53c71d09 2281\r
8e3bc754 2282 @param VmPtr A pointer to a VM context.\r
2283\r
34e4e297 2284 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 2285 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2286\r
fb0b259e 2287**/\r
fb0b259e 2288EFI_STATUS\r
2289ExecuteMOVIn (\r
2290 IN VM_CONTEXT *VmPtr\r
2291 )\r
53c71d09 2292{\r
2293 UINT8 Opcode;\r
2294 UINT8 Operands;\r
2295 UINT8 Size;\r
2296 INT16 Index16;\r
2297 INT16 ImmedIndex16;\r
2298 INT32 ImmedIndex32;\r
2299 INT64 ImmedIndex64;\r
2300 UINT64 Op1;\r
2301\r
2302 //\r
2303 // Get the opcode and operands byte so we can get R1 and R2\r
2304 //\r
2305 Opcode = GETOPCODE (VmPtr);\r
2306 Operands = GETOPERANDS (VmPtr);\r
2307\r
2308 //\r
2309 // Get the operand1 index (16-bit) if present\r
2310 //\r
366219ab 2311 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2312 Index16 = VmReadIndex16 (VmPtr, 2);\r
2313 Size = 4;\r
2314 } else {\r
2315 Index16 = 0;\r
2316 Size = 2;\r
2317 }\r
2318 //\r
2319 // Extract the immediate data and convert to a 64-bit index.\r
2320 //\r
2321 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
2322 ImmedIndex16 = VmReadIndex16 (VmPtr, Size);\r
2323 ImmedIndex64 = (INT64) ImmedIndex16;\r
2324 Size += 2;\r
2325 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
2326 ImmedIndex32 = VmReadIndex32 (VmPtr, Size);\r
2327 ImmedIndex64 = (INT64) ImmedIndex32;\r
2328 Size += 4;\r
2329 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
2330 ImmedIndex64 = VmReadIndex64 (VmPtr, Size);\r
2331 Size += 8;\r
2332 } else {\r
2333 //\r
2334 // Invalid encoding\r
2335 //\r
2336 EbcDebugSignalException (\r
2337 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2338 EXCEPTION_FLAG_FATAL,\r
2339 VmPtr\r
2340 );\r
2341 return EFI_UNSUPPORTED;\r
2342 }\r
2343 //\r
2344 // Now write back the result\r
2345 //\r
2346 if (!OPERAND1_INDIRECT (Operands)) {\r
2347 //\r
2348 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which\r
2349 // is illegal\r
2350 //\r
366219ab 2351 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2352 EbcDebugSignalException (\r
2353 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2354 EXCEPTION_FLAG_FATAL,\r
2355 VmPtr\r
2356 );\r
2357 return EFI_UNSUPPORTED;\r
2358 }\r
2359\r
1ccdbf2a 2360 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmedIndex64;\r
53c71d09 2361 } else {\r
2362 //\r
2363 // Get the address\r
2364 //\r
1ccdbf2a 2365 Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;\r
fbe12b79 2366 VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN)(INTN) ImmedIndex64);\r
53c71d09 2367 }\r
2368 //\r
2369 // Advance the instruction pointer\r
2370 //\r
2371 VmPtr->Ip += Size;\r
2372 return EFI_SUCCESS;\r
2373}\r
2374\r
53c71d09 2375\r
fb0b259e 2376/**\r
53c71d09 2377 Execute the EBC MOVREL instruction.\r
2378 Dest <- Ip + ImmData\r
2379\r
8e3bc754 2380 Instruction syntax:\r
34e4e297 2381\r
8e3bc754 2382 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
2383\r
2384 @param VmPtr A pointer to a VM context.\r
53c71d09 2385\r
34e4e297 2386 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 2387 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2388\r
fb0b259e 2389**/\r
fb0b259e 2390EFI_STATUS\r
2391ExecuteMOVREL (\r
2392 IN VM_CONTEXT *VmPtr\r
2393 )\r
53c71d09 2394{\r
2395 UINT8 Opcode;\r
2396 UINT8 Operands;\r
2397 UINT8 Size;\r
2398 INT16 Index16;\r
2399 INT64 ImmData64;\r
2400 UINT64 Op1;\r
2401 UINT64 Op2;\r
2402\r
2403 //\r
2404 // Get the opcode and operands byte so we can get R1 and R2\r
2405 //\r
2406 Opcode = GETOPCODE (VmPtr);\r
2407 Operands = GETOPERANDS (VmPtr);\r
2408\r
2409 //\r
2410 // Get the Operand 1 index (16-bit) if present\r
2411 //\r
366219ab 2412 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2413 Index16 = VmReadIndex16 (VmPtr, 2);\r
2414 Size = 4;\r
2415 } else {\r
2416 Index16 = 0;\r
2417 Size = 2;\r
2418 }\r
2419 //\r
2420 // Get the immediate data.\r
2421 //\r
2422 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
2423 ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);\r
2424 Size += 2;\r
2425 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
2426 ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);\r
2427 Size += 4;\r
2428 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
2429 ImmData64 = VmReadImmed64 (VmPtr, Size);\r
2430 Size += 8;\r
2431 } else {\r
2432 //\r
2433 // Invalid encoding\r
2434 //\r
2435 EbcDebugSignalException (\r
2436 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2437 EXCEPTION_FLAG_FATAL,\r
2438 VmPtr\r
2439 );\r
2440 return EFI_UNSUPPORTED;\r
2441 }\r
2442 //\r
2443 // Compute the value and write back the result\r
2444 //\r
2445 Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);\r
2446 if (!OPERAND1_INDIRECT (Operands)) {\r
2447 //\r
2448 // Check for illegal combination of operand1 direct with immediate data\r
2449 //\r
366219ab 2450 if ((Operands & MOVI_M_IMMDATA) != 0) {\r
53c71d09 2451 EbcDebugSignalException (\r
2452 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2453 EXCEPTION_FLAG_FATAL,\r
2454 VmPtr\r
2455 );\r
2456 return EFI_UNSUPPORTED;\r
2457 }\r
2458\r
1ccdbf2a 2459 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;\r
53c71d09 2460 } else {\r
2461 //\r
2462 // Get the address = [Rx] + Index16\r
2463 // Write back the result. Always a natural size write, since\r
2464 // we're talking addresses here.\r
2465 //\r
1ccdbf2a 2466 Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;\r
53c71d09 2467 VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);\r
2468 }\r
2469 //\r
2470 // Advance the instruction pointer\r
2471 //\r
2472 VmPtr->Ip += Size;\r
2473 return EFI_SUCCESS;\r
2474}\r
2475\r
53c71d09 2476\r
fb0b259e 2477/**\r
2478 Execute the EBC MOVsnw instruction. This instruction loads a signed\r
53c71d09 2479 natural value from memory or register to another memory or register. On\r
2480 32-bit machines, the value gets sign-extended to 64 bits if the destination\r
2481 is a register.\r
2482\r
8e3bc754 2483 Instruction syntax:\r
34e4e297 2484\r
8e3bc754 2485 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}\r
34e4e297 2486\r
8e3bc754 2487 0:7 1=>operand1 index present\r
2488 0:6 1=>operand2 index present\r
53c71d09 2489\r
8e3bc754 2490 @param VmPtr A pointer to a VM context.\r
2491\r
34e4e297 2492 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 2493 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2494\r
fb0b259e 2495**/\r
fb0b259e 2496EFI_STATUS\r
2497ExecuteMOVsnw (\r
2498 IN VM_CONTEXT *VmPtr\r
2499 )\r
53c71d09 2500{\r
2501 UINT8 Opcode;\r
2502 UINT8 Operands;\r
2503 UINT8 Size;\r
2504 INT16 Op1Index;\r
2505 INT16 Op2Index;\r
2506 UINT64 Op2;\r
2507\r
2508 //\r
2509 // Get the opcode and operand bytes\r
2510 //\r
2511 Opcode = GETOPCODE (VmPtr);\r
2512 Operands = GETOPERANDS (VmPtr);\r
2513\r
2514 Op1Index = Op2Index = 0;\r
2515\r
2516 //\r
2517 // Get the indexes if present.\r
2518 //\r
2519 Size = 2;\r
366219ab 2520 if ((Opcode & OPCODE_M_IMMED_OP1) !=0) {\r
53c71d09 2521 if (OPERAND1_INDIRECT (Operands)) {\r
2522 Op1Index = VmReadIndex16 (VmPtr, 2);\r
2523 } else {\r
2524 //\r
2525 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2\r
2526 //\r
2527 EbcDebugSignalException (\r
2528 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2529 EXCEPTION_FLAG_FATAL,\r
2530 VmPtr\r
2531 );\r
2532 return EFI_UNSUPPORTED;\r
2533 }\r
2534\r
2535 Size += sizeof (UINT16);\r
2536 }\r
2537\r
366219ab 2538 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 2539 if (OPERAND2_INDIRECT (Operands)) {\r
2540 Op2Index = VmReadIndex16 (VmPtr, Size);\r
2541 } else {\r
2542 Op2Index = VmReadImmed16 (VmPtr, Size);\r
2543 }\r
2544\r
2545 Size += sizeof (UINT16);\r
2546 }\r
2547 //\r
2548 // Get the data from the source.\r
2549 //\r
fa97cbf4 2550 Op2 = (UINT64)(INT64)(INTN)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);\r
53c71d09 2551 if (OPERAND2_INDIRECT (Operands)) {\r
fa97cbf4 2552 Op2 = (UINT64)(INT64)(INTN)VmReadMemN (VmPtr, (UINTN) Op2);\r
53c71d09 2553 }\r
2554 //\r
2555 // Now write back the result.\r
2556 //\r
2557 if (!OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2558 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;\r
53c71d09 2559 } else {\r
1ccdbf2a 2560 VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);\r
53c71d09 2561 }\r
2562 //\r
2563 // Advance the instruction pointer\r
2564 //\r
2565 VmPtr->Ip += Size;\r
2566 return EFI_SUCCESS;\r
2567}\r
2568\r
53c71d09 2569\r
fb0b259e 2570/**\r
2571 Execute the EBC MOVsnw instruction. This instruction loads a signed\r
53c71d09 2572 natural value from memory or register to another memory or register. On\r
2573 32-bit machines, the value gets sign-extended to 64 bits if the destination\r
2574 is a register.\r
2575\r
8e3bc754 2576 Instruction syntax:\r
34e4e297 2577\r
8e3bc754 2578 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}\r
34e4e297 2579\r
8e3bc754 2580 0:7 1=>operand1 index present\r
2581 0:6 1=>operand2 index present\r
2582\r
2583 @param VmPtr A pointer to a VM context.\r
53c71d09 2584\r
34e4e297 2585 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 2586 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2587\r
fb0b259e 2588**/\r
fb0b259e 2589EFI_STATUS\r
2590ExecuteMOVsnd (\r
2591 IN VM_CONTEXT *VmPtr\r
2592 )\r
53c71d09 2593{\r
2594 UINT8 Opcode;\r
2595 UINT8 Operands;\r
2596 UINT8 Size;\r
2597 INT32 Op1Index;\r
2598 INT32 Op2Index;\r
2599 UINT64 Op2;\r
2600\r
2601 //\r
2602 // Get the opcode and operand bytes\r
2603 //\r
2604 Opcode = GETOPCODE (VmPtr);\r
2605 Operands = GETOPERANDS (VmPtr);\r
2606\r
2607 Op1Index = Op2Index = 0;\r
2608\r
2609 //\r
2610 // Get the indexes if present.\r
2611 //\r
2612 Size = 2;\r
366219ab 2613 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {\r
53c71d09 2614 if (OPERAND1_INDIRECT (Operands)) {\r
2615 Op1Index = VmReadIndex32 (VmPtr, 2);\r
2616 } else {\r
2617 //\r
2618 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..\r
2619 //\r
2620 EbcDebugSignalException (\r
2621 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2622 EXCEPTION_FLAG_FATAL,\r
2623 VmPtr\r
2624 );\r
2625 return EFI_UNSUPPORTED;\r
2626 }\r
2627\r
2628 Size += sizeof (UINT32);\r
2629 }\r
2630\r
366219ab 2631 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {\r
53c71d09 2632 if (OPERAND2_INDIRECT (Operands)) {\r
2633 Op2Index = VmReadIndex32 (VmPtr, Size);\r
2634 } else {\r
2635 Op2Index = VmReadImmed32 (VmPtr, Size);\r
2636 }\r
2637\r
2638 Size += sizeof (UINT32);\r
2639 }\r
2640 //\r
2641 // Get the data from the source.\r
2642 //\r
fa97cbf4 2643 Op2 = (UINT64)(INT64)(INTN)(INT64)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);\r
53c71d09 2644 if (OPERAND2_INDIRECT (Operands)) {\r
fa97cbf4 2645 Op2 = (UINT64)(INT64)(INTN)(INT64)VmReadMemN (VmPtr, (UINTN) Op2);\r
53c71d09 2646 }\r
2647 //\r
2648 // Now write back the result.\r
2649 //\r
2650 if (!OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2651 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;\r
53c71d09 2652 } else {\r
1ccdbf2a 2653 VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);\r
53c71d09 2654 }\r
2655 //\r
2656 // Advance the instruction pointer\r
2657 //\r
2658 VmPtr->Ip += Size;\r
2659 return EFI_SUCCESS;\r
2660}\r
2661\r
53c71d09 2662\r
fb0b259e 2663/**\r
53c71d09 2664 Execute the EBC PUSHn instruction\r
2665\r
8e3bc754 2666 Instruction syntax:\r
2667 PUSHn {@}R1 {Index16|Immed16}\r
53c71d09 2668\r
8e3bc754 2669 @param VmPtr A pointer to a VM context.\r
2670\r
2671 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2672\r
fb0b259e 2673**/\r
fb0b259e 2674EFI_STATUS\r
2675ExecutePUSHn (\r
2676 IN VM_CONTEXT *VmPtr\r
2677 )\r
53c71d09 2678{\r
2679 UINT8 Opcode;\r
2680 UINT8 Operands;\r
2681 INT16 Index16;\r
2682 UINTN DataN;\r
2683\r
2684 //\r
2685 // Get opcode and operands\r
2686 //\r
2687 Opcode = GETOPCODE (VmPtr);\r
2688 Operands = GETOPERANDS (VmPtr);\r
2689\r
2690 //\r
2691 // Get index if present\r
2692 //\r
366219ab 2693 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {\r
53c71d09 2694 if (OPERAND1_INDIRECT (Operands)) {\r
2695 Index16 = VmReadIndex16 (VmPtr, 2);\r
2696 } else {\r
2697 Index16 = VmReadImmed16 (VmPtr, 2);\r
2698 }\r
2699\r
2700 VmPtr->Ip += 4;\r
2701 } else {\r
2702 Index16 = 0;\r
2703 VmPtr->Ip += 2;\r
2704 }\r
2705 //\r
2706 // Get the data to push\r
2707 //\r
2708 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2709 DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));\r
53c71d09 2710 } else {\r
1ccdbf2a 2711 DataN = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16);\r
53c71d09 2712 }\r
2713 //\r
2714 // Adjust the stack down.\r
2715 //\r
1ccdbf2a 2716 VmPtr->Gpr[0] -= sizeof (UINTN);\r
2717 VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], DataN);\r
53c71d09 2718 return EFI_SUCCESS;\r
2719}\r
2720\r
53c71d09 2721\r
fb0b259e 2722/**\r
8e3bc754 2723 Execute the EBC PUSH instruction.\r
2724\r
2725 Instruction syntax:\r
2726 PUSH[32|64] {@}R1 {Index16|Immed16}\r
53c71d09 2727\r
8e3bc754 2728 @param VmPtr A pointer to a VM context.\r
53c71d09 2729\r
8e3bc754 2730 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2731\r
fb0b259e 2732**/\r
fb0b259e 2733EFI_STATUS\r
2734ExecutePUSH (\r
2735 IN VM_CONTEXT *VmPtr\r
2736 )\r
53c71d09 2737{\r
2738 UINT8 Opcode;\r
2739 UINT8 Operands;\r
2740 UINT32 Data32;\r
2741 UINT64 Data64;\r
2742 INT16 Index16;\r
2743\r
2744 //\r
2745 // Get opcode and operands\r
2746 //\r
2747 Opcode = GETOPCODE (VmPtr);\r
2748 Operands = GETOPERANDS (VmPtr);\r
2749 //\r
2750 // Get immediate index if present, then advance the IP.\r
2751 //\r
366219ab 2752 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {\r
53c71d09 2753 if (OPERAND1_INDIRECT (Operands)) {\r
2754 Index16 = VmReadIndex16 (VmPtr, 2);\r
2755 } else {\r
2756 Index16 = VmReadImmed16 (VmPtr, 2);\r
2757 }\r
2758\r
2759 VmPtr->Ip += 4;\r
2760 } else {\r
2761 Index16 = 0;\r
2762 VmPtr->Ip += 2;\r
2763 }\r
2764 //\r
2765 // Get the data to push\r
2766 //\r
366219ab 2767 if ((Opcode & PUSHPOP_M_64) != 0) {\r
53c71d09 2768 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2769 Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));\r
53c71d09 2770 } else {\r
1ccdbf2a 2771 Data64 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;\r
53c71d09 2772 }\r
2773 //\r
2774 // Adjust the stack down, then write back the data\r
2775 //\r
1ccdbf2a 2776 VmPtr->Gpr[0] -= sizeof (UINT64);\r
2777 VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], Data64);\r
53c71d09 2778 } else {\r
2779 //\r
2780 // 32-bit data\r
2781 //\r
2782 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2783 Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));\r
53c71d09 2784 } else {\r
1ccdbf2a 2785 Data32 = (UINT32) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;\r
53c71d09 2786 }\r
2787 //\r
2788 // Adjust the stack down and write the data\r
2789 //\r
1ccdbf2a 2790 VmPtr->Gpr[0] -= sizeof (UINT32);\r
2791 VmWriteMem32 (VmPtr, (UINTN) VmPtr->Gpr[0], Data32);\r
53c71d09 2792 }\r
2793\r
2794 return EFI_SUCCESS;\r
2795}\r
2796\r
53c71d09 2797\r
fb0b259e 2798/**\r
8e3bc754 2799 Execute the EBC POPn instruction.\r
53c71d09 2800\r
8e3bc754 2801 Instruction syntax:\r
2802 POPn {@}R1 {Index16|Immed16}\r
53c71d09 2803\r
8e3bc754 2804 @param VmPtr A pointer to a VM context.\r
2805\r
2806 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2807\r
fb0b259e 2808**/\r
fb0b259e 2809EFI_STATUS\r
2810ExecutePOPn (\r
2811 IN VM_CONTEXT *VmPtr\r
2812 )\r
53c71d09 2813{\r
2814 UINT8 Opcode;\r
2815 UINT8 Operands;\r
2816 INT16 Index16;\r
2817 UINTN DataN;\r
2818\r
2819 //\r
2820 // Get opcode and operands\r
2821 //\r
2822 Opcode = GETOPCODE (VmPtr);\r
2823 Operands = GETOPERANDS (VmPtr);\r
2824 //\r
2825 // Get immediate data if present, and advance the IP\r
2826 //\r
366219ab 2827 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {\r
53c71d09 2828 if (OPERAND1_INDIRECT (Operands)) {\r
2829 Index16 = VmReadIndex16 (VmPtr, 2);\r
2830 } else {\r
2831 Index16 = VmReadImmed16 (VmPtr, 2);\r
2832 }\r
2833\r
2834 VmPtr->Ip += 4;\r
2835 } else {\r
2836 Index16 = 0;\r
2837 VmPtr->Ip += 2;\r
2838 }\r
2839 //\r
2840 // Read the data off the stack, then adjust the stack pointer\r
2841 //\r
1ccdbf2a 2842 DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);\r
2843 VmPtr->Gpr[0] += sizeof (UINTN);\r
53c71d09 2844 //\r
2845 // Do the write-back\r
2846 //\r
2847 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2848 VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), DataN);\r
53c71d09 2849 } else {\r
1ccdbf2a 2850 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16);\r
53c71d09 2851 }\r
2852\r
2853 return EFI_SUCCESS;\r
2854}\r
2855\r
53c71d09 2856\r
fb0b259e 2857/**\r
8e3bc754 2858 Execute the EBC POP instruction.\r
2859\r
2860 Instruction syntax:\r
2861 POPn {@}R1 {Index16|Immed16}\r
53c71d09 2862\r
8e3bc754 2863 @param VmPtr A pointer to a VM context.\r
53c71d09 2864\r
8e3bc754 2865 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2866\r
fb0b259e 2867**/\r
fb0b259e 2868EFI_STATUS\r
2869ExecutePOP (\r
2870 IN VM_CONTEXT *VmPtr\r
2871 )\r
53c71d09 2872{\r
2873 UINT8 Opcode;\r
2874 UINT8 Operands;\r
2875 INT16 Index16;\r
2876 INT32 Data32;\r
2877 UINT64 Data64;\r
2878\r
2879 //\r
2880 // Get opcode and operands\r
2881 //\r
2882 Opcode = GETOPCODE (VmPtr);\r
2883 Operands = GETOPERANDS (VmPtr);\r
2884 //\r
2885 // Get immediate data if present, and advance the IP.\r
2886 //\r
366219ab 2887 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {\r
53c71d09 2888 if (OPERAND1_INDIRECT (Operands)) {\r
2889 Index16 = VmReadIndex16 (VmPtr, 2);\r
2890 } else {\r
2891 Index16 = VmReadImmed16 (VmPtr, 2);\r
2892 }\r
2893\r
2894 VmPtr->Ip += 4;\r
2895 } else {\r
2896 Index16 = 0;\r
2897 VmPtr->Ip += 2;\r
2898 }\r
2899 //\r
2900 // Get the data off the stack, then write it to the appropriate location\r
2901 //\r
366219ab 2902 if ((Opcode & PUSHPOP_M_64) != 0) {\r
53c71d09 2903 //\r
2904 // Read the data off the stack, then adjust the stack pointer\r
2905 //\r
1ccdbf2a 2906 Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);\r
2907 VmPtr->Gpr[0] += sizeof (UINT64);\r
53c71d09 2908 //\r
2909 // Do the write-back\r
2910 //\r
2911 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2912 VmWriteMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data64);\r
53c71d09 2913 } else {\r
1ccdbf2a 2914 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 + Index16;\r
53c71d09 2915 }\r
2916 } else {\r
2917 //\r
2918 // 32-bit pop. Read it off the stack and adjust the stack pointer\r
2919 //\r
1ccdbf2a 2920 Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[0]);\r
2921 VmPtr->Gpr[0] += sizeof (UINT32);\r
53c71d09 2922 //\r
2923 // Do the write-back\r
2924 //\r
2925 if (OPERAND1_INDIRECT (Operands)) {\r
1ccdbf2a 2926 VmWriteMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data32);\r
53c71d09 2927 } else {\r
1ccdbf2a 2928 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;\r
53c71d09 2929 }\r
2930 }\r
2931\r
2932 return EFI_SUCCESS;\r
2933}\r
2934\r
53c71d09 2935\r
fb0b259e 2936/**\r
53c71d09 2937 Implements the EBC CALL instruction.\r
8e3bc754 2938\r
fb0b259e 2939 Instruction format:\r
8e3bc754 2940 CALL64 Immed64\r
2941 CALL32 {@}R1 {Immed32|Index32}\r
2942 CALLEX64 Immed64\r
2943 CALLEX16 {@}R1 {Immed32}\r
2944\r
2945 If Rx == R0, then it's a PC relative call to PC = PC + imm32.\r
53c71d09 2946\r
8e3bc754 2947 @param VmPtr A pointer to a VM context.\r
fb0b259e 2948\r
8e3bc754 2949 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 2950\r
fb0b259e 2951**/\r
fb0b259e 2952EFI_STATUS\r
2953ExecuteCALL (\r
2954 IN VM_CONTEXT *VmPtr\r
2955 )\r
53c71d09 2956{\r
2957 UINT8 Opcode;\r
2958 UINT8 Operands;\r
2959 INT32 Immed32;\r
2960 UINT8 Size;\r
2961 INT64 Immed64;\r
2962 VOID *FramePtr;\r
2963\r
2964 //\r
2965 // Get opcode and operands\r
2966 //\r
2967 Opcode = GETOPCODE (VmPtr);\r
2968 Operands = GETOPERANDS (VmPtr);\r
2969 //\r
2970 // Assign these as well to avoid compiler warnings\r
2971 //\r
2972 Immed64 = 0;\r
2973 Immed32 = 0;\r
2974\r
2975 FramePtr = VmPtr->FramePtr;\r
2976 //\r
2977 // Determine the instruction size, and get immediate data if present\r
2978 //\r
366219ab 2979 if ((Opcode & OPCODE_M_IMMDATA) != 0) {\r
2980 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {\r
53c71d09 2981 Immed64 = VmReadImmed64 (VmPtr, 2);\r
2982 Size = 10;\r
2983 } else {\r
2984 //\r
2985 // If register operand is indirect, then the immediate data is an index\r
2986 //\r
2987 if (OPERAND1_INDIRECT (Operands)) {\r
2988 Immed32 = VmReadIndex32 (VmPtr, 2);\r
2989 } else {\r
2990 Immed32 = VmReadImmed32 (VmPtr, 2);\r
2991 }\r
2992\r
2993 Size = 6;\r
2994 }\r
2995 } else {\r
2996 Size = 2;\r
2997 }\r
2998 //\r
2999 // If it's a call to EBC, adjust the stack pointer down 16 bytes and\r
3000 // put our return address and frame pointer on the VM stack.\r
3001 //\r
3002 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
1ccdbf2a 3003 VmPtr->Gpr[0] -= 8;\r
3004 VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);\r
3005 VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];\r
3006 VmPtr->Gpr[0] -= 8;\r
3007 VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));\r
53c71d09 3008 }\r
3009 //\r
3010 // If 64-bit data, then absolute jump only\r
3011 //\r
366219ab 3012 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {\r
53c71d09 3013 //\r
3014 // Native or EBC call?\r
3015 //\r
3016 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
3017 VmPtr->Ip = (VMIP) (UINTN) Immed64;\r
3018 } else {\r
3019 //\r
3020 // Call external function, get the return value, and advance the IP\r
3021 //\r
1ccdbf2a 3022 EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);\r
53c71d09 3023 }\r
3024 } else {\r
3025 //\r
3026 // Get the register data. If operand1 == 0, then ignore register and\r
3027 // take immediate data as relative or absolute address.\r
3028 // Compiler should take care of upper bits if 32-bit machine.\r
3029 //\r
3030 if (OPERAND1_REGNUM (Operands) != 0) {\r
1ccdbf2a 3031 Immed64 = (UINT64) (UINTN) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];\r
53c71d09 3032 }\r
3033 //\r
3034 // Get final address\r
3035 //\r
3036 if (OPERAND1_INDIRECT (Operands)) {\r
3037 Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));\r
3038 } else {\r
3039 Immed64 += Immed32;\r
3040 }\r
3041 //\r
3042 // Now determine if external call, and then if relative or absolute\r
3043 //\r
3044 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
3045 //\r
3046 // EBC call. Relative or absolute? If relative, then it's relative to the\r
3047 // start of the next instruction.\r
3048 //\r
366219ab 3049 if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {\r
53c71d09 3050 VmPtr->Ip += Immed64 + Size;\r
3051 } else {\r
3052 VmPtr->Ip = (VMIP) (UINTN) Immed64;\r
3053 }\r
3054 } else {\r
3055 //\r
3056 // Native call. Relative or absolute?\r
3057 //\r
366219ab 3058 if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {\r
1ccdbf2a 3059 EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->Gpr[0], FramePtr, Size);\r
53c71d09 3060 } else {\r
366219ab 3061 if ((VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) != 0) {\r
53c71d09 3062 CpuBreakpoint ();\r
3063 }\r
3064\r
1ccdbf2a 3065 EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);\r
53c71d09 3066 }\r
3067 }\r
3068 }\r
3069\r
3070 return EFI_SUCCESS;\r
3071}\r
3072\r
53c71d09 3073\r
fb0b259e 3074/**\r
8e3bc754 3075 Execute the EBC RET instruction.\r
53c71d09 3076\r
8e3bc754 3077 Instruction syntax:\r
3078 RET\r
53c71d09 3079\r
8e3bc754 3080 @param VmPtr A pointer to a VM context.\r
3081\r
3082 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 3083\r
fb0b259e 3084**/\r
fb0b259e 3085EFI_STATUS\r
3086ExecuteRET (\r
3087 IN VM_CONTEXT *VmPtr\r
3088 )\r
53c71d09 3089{\r
3090 //\r
3091 // If we're at the top of the stack, then simply set the done\r
3092 // flag and return\r
3093 //\r
1ccdbf2a 3094 if (VmPtr->StackRetAddr == (UINT64) VmPtr->Gpr[0]) {\r
53c71d09 3095 VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
3096 } else {\r
3097 //\r
3098 // Pull the return address off the VM app's stack and set the IP\r
3099 // to it\r
3100 //\r
1ccdbf2a 3101 if (!IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {\r
53c71d09 3102 EbcDebugSignalException (\r
3103 EXCEPT_EBC_ALIGNMENT_CHECK,\r
3104 EXCEPTION_FLAG_FATAL,\r
3105 VmPtr\r
3106 );\r
3107 }\r
3108 //\r
3109 // Restore the IP and frame pointer from the stack\r
3110 //\r
1ccdbf2a 3111 VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);\r
3112 VmPtr->Gpr[0] += 8;\r
3113 VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);\r
3114 VmPtr->Gpr[0] += 8;\r
53c71d09 3115 }\r
3116\r
3117 return EFI_SUCCESS;\r
3118}\r
3119\r
53c71d09 3120\r
fb0b259e 3121/**\r
8e3bc754 3122 Execute the EBC CMP instruction.\r
3123\r
3124 Instruction syntax:\r
3125 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}\r
53c71d09 3126\r
8e3bc754 3127 @param VmPtr A pointer to a VM context.\r
53c71d09 3128\r
34e4e297 3129 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 3130 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 3131\r
fb0b259e 3132**/\r
fb0b259e 3133EFI_STATUS\r
3134ExecuteCMP (\r
3135 IN VM_CONTEXT *VmPtr\r
3136 )\r
53c71d09 3137{\r
3138 UINT8 Opcode;\r
3139 UINT8 Operands;\r
3140 UINT8 Size;\r
3141 INT16 Index16;\r
3142 UINT32 Flag;\r
3143 INT64 Op2;\r
3144 INT64 Op1;\r
3145\r
3146 //\r
3147 // Get opcode and operands\r
3148 //\r
3149 Opcode = GETOPCODE (VmPtr);\r
3150 Operands = GETOPERANDS (VmPtr);\r
3151 //\r
3152 // Get the register data we're going to compare to\r
3153 //\r
1ccdbf2a 3154 Op1 = VmPtr->Gpr[OPERAND1_REGNUM (Operands)];\r
53c71d09 3155 //\r
3156 // Get immediate data\r
3157 //\r
366219ab 3158 if ((Opcode & OPCODE_M_IMMDATA) != 0) {\r
53c71d09 3159 if (OPERAND2_INDIRECT (Operands)) {\r
3160 Index16 = VmReadIndex16 (VmPtr, 2);\r
3161 } else {\r
3162 Index16 = VmReadImmed16 (VmPtr, 2);\r
3163 }\r
3164\r
3165 Size = 4;\r
3166 } else {\r
3167 Index16 = 0;\r
3168 Size = 2;\r
3169 }\r
3170 //\r
3171 // Now get Op2\r
3172 //\r
3173 if (OPERAND2_INDIRECT (Operands)) {\r
366219ab 3174 if ((Opcode & OPCODE_M_64BIT) != 0) {\r
1ccdbf2a 3175 Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16));\r
53c71d09 3176 } else {\r
3177 //\r
3178 // 32-bit operations. 0-extend the values for all cases.\r
3179 //\r
1ccdbf2a 3180 Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16)));\r
53c71d09 3181 }\r
3182 } else {\r
1ccdbf2a 3183 Op2 = VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;\r
53c71d09 3184 }\r
3185 //\r
3186 // Now do the compare\r
3187 //\r
3188 Flag = 0;\r
366219ab 3189 if ((Opcode & OPCODE_M_64BIT) != 0) {\r
53c71d09 3190 //\r
3191 // 64-bit compares\r
3192 //\r
3193 switch (Opcode & OPCODE_M_OPCODE) {\r
3194 case OPCODE_CMPEQ:\r
3195 if (Op1 == Op2) {\r
3196 Flag = 1;\r
3197 }\r
3198 break;\r
3199\r
3200 case OPCODE_CMPLTE:\r
3201 if (Op1 <= Op2) {\r
3202 Flag = 1;\r
3203 }\r
3204 break;\r
3205\r
3206 case OPCODE_CMPGTE:\r
3207 if (Op1 >= Op2) {\r
3208 Flag = 1;\r
3209 }\r
3210 break;\r
3211\r
3212 case OPCODE_CMPULTE:\r
3213 if ((UINT64) Op1 <= (UINT64) Op2) {\r
3214 Flag = 1;\r
3215 }\r
3216 break;\r
3217\r
3218 case OPCODE_CMPUGTE:\r
3219 if ((UINT64) Op1 >= (UINT64) Op2) {\r
3220 Flag = 1;\r
3221 }\r
3222 break;\r
3223\r
3224 default:\r
3225 ASSERT (0);\r
3226 }\r
3227 } else {\r
3228 //\r
3229 // 32-bit compares\r
3230 //\r
3231 switch (Opcode & OPCODE_M_OPCODE) {\r
3232 case OPCODE_CMPEQ:\r
3233 if ((INT32) Op1 == (INT32) Op2) {\r
3234 Flag = 1;\r
3235 }\r
3236 break;\r
3237\r
3238 case OPCODE_CMPLTE:\r
3239 if ((INT32) Op1 <= (INT32) Op2) {\r
3240 Flag = 1;\r
3241 }\r
3242 break;\r
3243\r
3244 case OPCODE_CMPGTE:\r
3245 if ((INT32) Op1 >= (INT32) Op2) {\r
3246 Flag = 1;\r
3247 }\r
3248 break;\r
3249\r
3250 case OPCODE_CMPULTE:\r
3251 if ((UINT32) Op1 <= (UINT32) Op2) {\r
3252 Flag = 1;\r
3253 }\r
3254 break;\r
3255\r
3256 case OPCODE_CMPUGTE:\r
3257 if ((UINT32) Op1 >= (UINT32) Op2) {\r
3258 Flag = 1;\r
3259 }\r
3260 break;\r
3261\r
3262 default:\r
3263 ASSERT (0);\r
3264 }\r
3265 }\r
3266 //\r
3267 // Now set the flag accordingly for the comparison\r
3268 //\r
366219ab 3269 if (Flag != 0) {\r
53c71d09 3270 VMFLAG_SET (VmPtr, VMFLAGS_CC);\r
3271 } else {\r
6e1e5405 3272 VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);\r
53c71d09 3273 }\r
3274 //\r
3275 // Advance the IP\r
3276 //\r
3277 VmPtr->Ip += Size;\r
3278 return EFI_SUCCESS;\r
3279}\r
3280\r
53c71d09 3281\r
fb0b259e 3282/**\r
53c71d09 3283 Execute the EBC CMPI instruction\r
3284\r
8e3bc754 3285 Instruction syntax:\r
3286 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32\r
53c71d09 3287\r
8e3bc754 3288 @param VmPtr A pointer to a VM context.\r
3289\r
34e4e297 3290 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 3291 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 3292\r
fb0b259e 3293**/\r
fb0b259e 3294EFI_STATUS\r
3295ExecuteCMPI (\r
3296 IN VM_CONTEXT *VmPtr\r
3297 )\r
53c71d09 3298{\r
3299 UINT8 Opcode;\r
3300 UINT8 Operands;\r
3301 UINT8 Size;\r
3302 INT64 Op1;\r
3303 INT64 Op2;\r
3304 INT16 Index16;\r
3305 UINT32 Flag;\r
3306\r
3307 //\r
3308 // Get opcode and operands\r
3309 //\r
3310 Opcode = GETOPCODE (VmPtr);\r
3311 Operands = GETOPERANDS (VmPtr);\r
3312\r
3313 //\r
3314 // Get operand1 index if present\r
3315 //\r
3316 Size = 2;\r
366219ab 3317 if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {\r
53c71d09 3318 Index16 = VmReadIndex16 (VmPtr, 2);\r
3319 Size += 2;\r
3320 } else {\r
3321 Index16 = 0;\r
3322 }\r
3323 //\r
3324 // Get operand1 data we're going to compare to\r
3325 //\r
1ccdbf2a 3326 Op1 = (INT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];\r
53c71d09 3327 if (OPERAND1_INDIRECT (Operands)) {\r
3328 //\r
3329 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.\r
3330 //\r
366219ab 3331 if ((Opcode & OPCODE_M_CMPI64) != 0) {\r
53c71d09 3332 Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);\r
3333 } else {\r
3334 Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);\r
3335 }\r
3336 } else {\r
3337 //\r
3338 // Better not have been an index with direct. That is, CMPI R1 Index,...\r
3339 // is illegal.\r
3340 //\r
366219ab 3341 if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {\r
53c71d09 3342 EbcDebugSignalException (\r
3343 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
3344 EXCEPTION_FLAG_ERROR,\r
3345 VmPtr\r
3346 );\r
3347 VmPtr->Ip += Size;\r
3348 return EFI_UNSUPPORTED;\r
3349 }\r
3350 }\r
3351 //\r
3352 // Get immediate data -- 16- or 32-bit sign extended\r
3353 //\r
366219ab 3354 if ((Opcode & OPCODE_M_CMPI32_DATA) != 0) {\r
53c71d09 3355 Op2 = (INT64) VmReadImmed32 (VmPtr, Size);\r
3356 Size += 4;\r
3357 } else {\r
3358 //\r
3359 // 16-bit immediate data. Sign extend always.\r
3360 //\r
3361 Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));\r
3362 Size += 2;\r
3363 }\r
3364 //\r
3365 // Now do the compare\r
3366 //\r
3367 Flag = 0;\r
366219ab 3368 if ((Opcode & OPCODE_M_CMPI64) != 0) {\r
53c71d09 3369 //\r
3370 // 64 bit comparison\r
3371 //\r
3372 switch (Opcode & OPCODE_M_OPCODE) {\r
3373 case OPCODE_CMPIEQ:\r
3374 if (Op1 == (INT64) Op2) {\r
3375 Flag = 1;\r
3376 }\r
3377 break;\r
3378\r
3379 case OPCODE_CMPILTE:\r
3380 if (Op1 <= (INT64) Op2) {\r
3381 Flag = 1;\r
3382 }\r
3383 break;\r
3384\r
3385 case OPCODE_CMPIGTE:\r
3386 if (Op1 >= (INT64) Op2) {\r
3387 Flag = 1;\r
3388 }\r
3389 break;\r
3390\r
3391 case OPCODE_CMPIULTE:\r
3392 if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {\r
3393 Flag = 1;\r
3394 }\r
3395 break;\r
3396\r
3397 case OPCODE_CMPIUGTE:\r
3398 if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {\r
3399 Flag = 1;\r
3400 }\r
3401 break;\r
3402\r
3403 default:\r
3404 ASSERT (0);\r
3405 }\r
3406 } else {\r
3407 //\r
3408 // 32-bit comparisons\r
3409 //\r
3410 switch (Opcode & OPCODE_M_OPCODE) {\r
3411 case OPCODE_CMPIEQ:\r
3412 if ((INT32) Op1 == Op2) {\r
3413 Flag = 1;\r
3414 }\r
3415 break;\r
3416\r
3417 case OPCODE_CMPILTE:\r
3418 if ((INT32) Op1 <= Op2) {\r
3419 Flag = 1;\r
3420 }\r
3421 break;\r
3422\r
3423 case OPCODE_CMPIGTE:\r
3424 if ((INT32) Op1 >= Op2) {\r
3425 Flag = 1;\r
3426 }\r
3427 break;\r
3428\r
3429 case OPCODE_CMPIULTE:\r
3430 if ((UINT32) Op1 <= (UINT32) Op2) {\r
3431 Flag = 1;\r
3432 }\r
3433 break;\r
3434\r
3435 case OPCODE_CMPIUGTE:\r
3436 if ((UINT32) Op1 >= (UINT32) Op2) {\r
3437 Flag = 1;\r
3438 }\r
3439 break;\r
3440\r
3441 default:\r
3442 ASSERT (0);\r
3443 }\r
3444 }\r
3445 //\r
3446 // Now set the flag accordingly for the comparison\r
3447 //\r
366219ab 3448 if (Flag != 0) {\r
53c71d09 3449 VMFLAG_SET (VmPtr, VMFLAGS_CC);\r
3450 } else {\r
6e1e5405 3451 VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);\r
53c71d09 3452 }\r
3453 //\r
3454 // Advance the IP\r
3455 //\r
3456 VmPtr->Ip += Size;\r
3457 return EFI_SUCCESS;\r
3458}\r
3459\r
fb0b259e 3460\r
3461/**\r
8e3bc754 3462 Execute the EBC NOT instruction.s\r
3463\r
3464 Instruction syntax:\r
3465 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3466\r
8e3bc754 3467 @param VmPtr A pointer to a VM context.\r
fb0b259e 3468 @param Op1 Operand 1 from the instruction\r
3469 @param Op2 Operand 2 from the instruction\r
3470\r
3471 @return ~Op2\r
fb0b259e 3472\r
3473**/\r
53c71d09 3474UINT64\r
3475ExecuteNOT (\r
3476 IN VM_CONTEXT *VmPtr,\r
3477 IN UINT64 Op1,\r
3478 IN UINT64 Op2\r
3479 )\r
fb0b259e 3480{\r
3481 return ~Op2;\r
3482}\r
53c71d09 3483\r
53c71d09 3484\r
fb0b259e 3485/**\r
8e3bc754 3486 Execute the EBC NEG instruction.\r
53c71d09 3487\r
8e3bc754 3488 Instruction syntax:\r
3489 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3490\r
3491 @param VmPtr A pointer to a VM context.\r
fb0b259e 3492 @param Op1 Operand 1 from the instruction\r
3493 @param Op2 Operand 2 from the instruction\r
53c71d09 3494\r
fb0b259e 3495 @return Op2 * -1\r
53c71d09 3496\r
fb0b259e 3497**/\r
53c71d09 3498UINT64\r
3499ExecuteNEG (\r
3500 IN VM_CONTEXT *VmPtr,\r
3501 IN UINT64 Op1,\r
3502 IN UINT64 Op2\r
3503 )\r
fb0b259e 3504{\r
3505 return ~Op2 + 1;\r
3506}\r
53c71d09 3507\r
53c71d09 3508\r
fb0b259e 3509/**\r
8e3bc754 3510 Execute the EBC ADD instruction.\r
3511\r
3512 Instruction syntax:\r
3513 ADD[32|64] {@}R1, {@}R2 {Index16}\r
53c71d09 3514\r
8e3bc754 3515 @param VmPtr A pointer to a VM context.\r
fb0b259e 3516 @param Op1 Operand 1 from the instruction\r
3517 @param Op2 Operand 2 from the instruction\r
53c71d09 3518\r
fb0b259e 3519 @return Op1 + Op2\r
53c71d09 3520\r
fb0b259e 3521**/\r
53c71d09 3522UINT64\r
3523ExecuteADD (\r
3524 IN VM_CONTEXT *VmPtr,\r
3525 IN UINT64 Op1,\r
3526 IN UINT64 Op2\r
3527 )\r
fb0b259e 3528{\r
3529 return Op1 + Op2;\r
3530}\r
53c71d09 3531\r
53c71d09 3532\r
fb0b259e 3533/**\r
8e3bc754 3534 Execute the EBC SUB instruction.\r
53c71d09 3535\r
8e3bc754 3536 Instruction syntax:\r
3537 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3538\r
3539 @param VmPtr A pointer to a VM context.\r
fb0b259e 3540 @param Op1 Operand 1 from the instruction\r
3541 @param Op2 Operand 2 from the instruction\r
53c71d09 3542\r
8e3bc754 3543 @return Op1 - Op2\r
53c71d09 3544\r
fb0b259e 3545**/\r
53c71d09 3546UINT64\r
3547ExecuteSUB (\r
3548 IN VM_CONTEXT *VmPtr,\r
3549 IN UINT64 Op1,\r
3550 IN UINT64 Op2\r
3551 )\r
53c71d09 3552{\r
366219ab 3553 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3554 return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));\r
3555 } else {\r
3556 return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2));\r
3557 }\r
3558}\r
3559\r
fb0b259e 3560\r
3561/**\r
8e3bc754 3562 Execute the EBC MUL instruction.\r
3563\r
3564 Instruction syntax:\r
3565 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3566\r
8e3bc754 3567 @param VmPtr A pointer to a VM context.\r
fb0b259e 3568 @param Op1 Operand 1 from the instruction\r
3569 @param Op2 Operand 2 from the instruction\r
3570\r
3571 @return Op1 * Op2\r
fb0b259e 3572\r
3573**/\r
53c71d09 3574UINT64\r
3575ExecuteMUL (\r
3576 IN VM_CONTEXT *VmPtr,\r
3577 IN UINT64 Op1,\r
3578 IN UINT64 Op2\r
3579 )\r
53c71d09 3580{\r
366219ab 3581 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3582 return MultS64x64 ((INT64)Op1, (INT64)Op2);\r
3583 } else {\r
3584 return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2));\r
3585 }\r
3586}\r
3587\r
fb0b259e 3588\r
3589/**\r
3590 Execute the EBC MULU instruction\r
3591\r
8e3bc754 3592 Instruction syntax:\r
3593 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3594\r
3595 @param VmPtr A pointer to a VM context.\r
fb0b259e 3596 @param Op1 Operand 1 from the instruction\r
3597 @param Op2 Operand 2 from the instruction\r
3598\r
3599 @return (unsigned)Op1 * (unsigned)Op2\r
fb0b259e 3600\r
3601**/\r
53c71d09 3602UINT64\r
3603ExecuteMULU (\r
3604 IN VM_CONTEXT *VmPtr,\r
3605 IN UINT64 Op1,\r
3606 IN UINT64 Op2\r
3607 )\r
53c71d09 3608{\r
366219ab 3609 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3610 return MultU64x64 (Op1, Op2);\r
3611 } else {\r
3612 return (UINT64) ((UINT32) Op1 * (UINT32) Op2);\r
3613 }\r
3614}\r
3615\r
fb0b259e 3616\r
3617/**\r
8e3bc754 3618 Execute the EBC DIV instruction.\r
3619\r
3620 Instruction syntax:\r
3621 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3622\r
8e3bc754 3623 @param VmPtr A pointer to a VM context.\r
fb0b259e 3624 @param Op1 Operand 1 from the instruction\r
3625 @param Op2 Operand 2 from the instruction\r
3626\r
8e3bc754 3627 @return Op1 / Op2\r
fb0b259e 3628\r
3629**/\r
53c71d09 3630UINT64\r
3631ExecuteDIV (\r
3632 IN VM_CONTEXT *VmPtr,\r
3633 IN UINT64 Op1,\r
3634 IN UINT64 Op2\r
3635 )\r
53c71d09 3636{\r
3637 INT64 Remainder;\r
3638\r
3639 //\r
3640 // Check for divide-by-0\r
3641 //\r
3642 if (Op2 == 0) {\r
3643 EbcDebugSignalException (\r
3644 EXCEPT_EBC_DIVIDE_ERROR,\r
3645 EXCEPTION_FLAG_FATAL,\r
3646 VmPtr\r
3647 );\r
3648\r
3649 return 0;\r
3650 } else {\r
366219ab 3651 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3652 return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));\r
3653 } else {\r
3654 return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));\r
3655 }\r
3656 }\r
3657}\r
3658\r
fb0b259e 3659\r
3660/**\r
3661 Execute the EBC DIVU instruction\r
3662\r
8e3bc754 3663 Instruction syntax:\r
3664 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3665\r
3666 @param VmPtr A pointer to a VM context.\r
fb0b259e 3667 @param Op1 Operand 1 from the instruction\r
3668 @param Op2 Operand 2 from the instruction\r
3669\r
3670 @return (unsigned)Op1 / (unsigned)Op2\r
fb0b259e 3671\r
3672**/\r
53c71d09 3673UINT64\r
3674ExecuteDIVU (\r
3675 IN VM_CONTEXT *VmPtr,\r
3676 IN UINT64 Op1,\r
3677 IN UINT64 Op2\r
3678 )\r
53c71d09 3679{\r
3680 UINT64 Remainder;\r
3681\r
3682 //\r
3683 // Check for divide-by-0\r
3684 //\r
3685 if (Op2 == 0) {\r
3686 EbcDebugSignalException (\r
3687 EXCEPT_EBC_DIVIDE_ERROR,\r
3688 EXCEPTION_FLAG_FATAL,\r
3689 VmPtr\r
3690 );\r
3691 return 0;\r
3692 } else {\r
3693 //\r
3694 // Get the destination register\r
3695 //\r
366219ab 3696 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
c9325700 3697 return (UINT64) (DivU64x64Remainder (Op1, Op2, &Remainder));\r
53c71d09 3698 } else {\r
3699 return (UINT64) ((UINT32) Op1 / (UINT32) Op2);\r
3700 }\r
3701 }\r
3702}\r
3703\r
fb0b259e 3704\r
3705/**\r
8e3bc754 3706 Execute the EBC MOD instruction.\r
3707\r
3708 Instruction syntax:\r
3709 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3710\r
8e3bc754 3711 @param VmPtr A pointer to a VM context.\r
fb0b259e 3712 @param Op1 Operand 1 from the instruction\r
3713 @param Op2 Operand 2 from the instruction\r
3714\r
3715 @return Op1 MODULUS Op2\r
fb0b259e 3716\r
3717**/\r
53c71d09 3718UINT64\r
3719ExecuteMOD (\r
3720 IN VM_CONTEXT *VmPtr,\r
3721 IN UINT64 Op1,\r
3722 IN UINT64 Op2\r
3723 )\r
53c71d09 3724{\r
3725 INT64 Remainder;\r
3726\r
3727 //\r
3728 // Check for divide-by-0\r
3729 //\r
3730 if (Op2 == 0) {\r
3731 EbcDebugSignalException (\r
3732 EXCEPT_EBC_DIVIDE_ERROR,\r
3733 EXCEPTION_FLAG_FATAL,\r
3734 VmPtr\r
3735 );\r
3736 return 0;\r
3737 } else {\r
3738 DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);\r
3739 return Remainder;\r
3740 }\r
3741}\r
3742\r
fb0b259e 3743\r
3744/**\r
8e3bc754 3745 Execute the EBC MODU instruction.\r
fb0b259e 3746\r
8e3bc754 3747 Instruction syntax:\r
3748 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3749\r
3750 @param VmPtr A pointer to a VM context.\r
fb0b259e 3751 @param Op1 Operand 1 from the instruction\r
3752 @param Op2 Operand 2 from the instruction\r
3753\r
3754 @return Op1 UNSIGNED_MODULUS Op2\r
fb0b259e 3755\r
3756**/\r
53c71d09 3757UINT64\r
3758ExecuteMODU (\r
3759 IN VM_CONTEXT *VmPtr,\r
3760 IN UINT64 Op1,\r
3761 IN UINT64 Op2\r
3762 )\r
53c71d09 3763{\r
3764 UINT64 Remainder;\r
3765\r
3766 //\r
3767 // Check for divide-by-0\r
3768 //\r
3769 if (Op2 == 0) {\r
3770 EbcDebugSignalException (\r
3771 EXCEPT_EBC_DIVIDE_ERROR,\r
3772 EXCEPTION_FLAG_FATAL,\r
3773 VmPtr\r
3774 );\r
3775 return 0;\r
3776 } else {\r
3777 DivU64x64Remainder (Op1, Op2, &Remainder);\r
3778 return Remainder;\r
3779 }\r
3780}\r
3781\r
fb0b259e 3782\r
3783/**\r
8e3bc754 3784 Execute the EBC AND instruction.\r
3785\r
3786 Instruction syntax:\r
3787 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3788\r
8e3bc754 3789 @param VmPtr A pointer to a VM context.\r
fb0b259e 3790 @param Op1 Operand 1 from the instruction\r
3791 @param Op2 Operand 2 from the instruction\r
3792\r
3793 @return Op1 AND Op2\r
fb0b259e 3794\r
3795**/\r
53c71d09 3796UINT64\r
3797ExecuteAND (\r
3798 IN VM_CONTEXT *VmPtr,\r
3799 IN UINT64 Op1,\r
3800 IN UINT64 Op2\r
3801 )\r
fb0b259e 3802{\r
3803 return Op1 & Op2;\r
3804}\r
53c71d09 3805\r
53c71d09 3806\r
fb0b259e 3807/**\r
8e3bc754 3808 Execute the EBC OR instruction.\r
53c71d09 3809\r
8e3bc754 3810 Instruction syntax:\r
3811 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3812\r
3813 @param VmPtr A pointer to a VM context.\r
fb0b259e 3814 @param Op1 Operand 1 from the instruction\r
3815 @param Op2 Operand 2 from the instruction\r
53c71d09 3816\r
fb0b259e 3817 @return Op1 OR Op2\r
53c71d09 3818\r
fb0b259e 3819**/\r
53c71d09 3820UINT64\r
3821ExecuteOR (\r
3822 IN VM_CONTEXT *VmPtr,\r
3823 IN UINT64 Op1,\r
3824 IN UINT64 Op2\r
3825 )\r
fb0b259e 3826{\r
3827 return Op1 | Op2;\r
3828}\r
53c71d09 3829\r
53c71d09 3830\r
fb0b259e 3831/**\r
8e3bc754 3832 Execute the EBC XOR instruction.\r
3833\r
3834 Instruction syntax:\r
3835 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
53c71d09 3836\r
8e3bc754 3837 @param VmPtr A pointer to a VM context.\r
fb0b259e 3838 @param Op1 Operand 1 from the instruction\r
3839 @param Op2 Operand 2 from the instruction\r
53c71d09 3840\r
fb0b259e 3841 @return Op1 XOR Op2\r
53c71d09 3842\r
fb0b259e 3843**/\r
53c71d09 3844UINT64\r
3845ExecuteXOR (\r
3846 IN VM_CONTEXT *VmPtr,\r
3847 IN UINT64 Op1,\r
3848 IN UINT64 Op2\r
3849 )\r
fb0b259e 3850{\r
3851 return Op1 ^ Op2;\r
3852}\r
53c71d09 3853\r
53c71d09 3854\r
fb0b259e 3855/**\r
8e3bc754 3856 Execute the EBC SHL shift left instruction.\r
53c71d09 3857\r
8e3bc754 3858 Instruction syntax:\r
3859 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3860\r
3861 @param VmPtr A pointer to a VM context.\r
fb0b259e 3862 @param Op1 Operand 1 from the instruction\r
3863 @param Op2 Operand 2 from the instruction\r
53c71d09 3864\r
fb0b259e 3865 @return Op1 << Op2\r
53c71d09 3866\r
fb0b259e 3867**/\r
53c71d09 3868UINT64\r
3869ExecuteSHL (\r
3870 IN VM_CONTEXT *VmPtr,\r
3871 IN UINT64 Op1,\r
3872 IN UINT64 Op2\r
3873 )\r
53c71d09 3874{\r
366219ab 3875 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3876 return LShiftU64 (Op1, (UINTN)Op2);\r
3877 } else {\r
3878 return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));\r
3879 }\r
3880}\r
3881\r
fb0b259e 3882\r
3883/**\r
8e3bc754 3884 Execute the EBC SHR instruction.\r
3885\r
3886 Instruction syntax:\r
3887 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
fb0b259e 3888\r
8e3bc754 3889 @param VmPtr A pointer to a VM context.\r
fb0b259e 3890 @param Op1 Operand 1 from the instruction\r
3891 @param Op2 Operand 2 from the instruction\r
3892\r
3893 @return Op1 >> Op2 (unsigned operands)\r
fb0b259e 3894\r
3895**/\r
53c71d09 3896UINT64\r
3897ExecuteSHR (\r
3898 IN VM_CONTEXT *VmPtr,\r
3899 IN UINT64 Op1,\r
3900 IN UINT64 Op2\r
3901 )\r
53c71d09 3902{\r
366219ab 3903 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3904 return RShiftU64 (Op1, (UINTN)Op2);\r
3905 } else {\r
3906 return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);\r
3907 }\r
3908}\r
3909\r
fb0b259e 3910\r
3911/**\r
8e3bc754 3912 Execute the EBC ASHR instruction.\r
fb0b259e 3913\r
8e3bc754 3914 Instruction syntax:\r
3915 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3916\r
3917 @param VmPtr A pointer to a VM context.\r
fb0b259e 3918 @param Op1 Operand 1 from the instruction\r
3919 @param Op2 Operand 2 from the instruction\r
3920\r
3921 @return Op1 >> Op2 (signed)\r
fb0b259e 3922\r
3923**/\r
53c71d09 3924UINT64\r
3925ExecuteASHR (\r
3926 IN VM_CONTEXT *VmPtr,\r
3927 IN UINT64 Op1,\r
3928 IN UINT64 Op2\r
3929 )\r
53c71d09 3930{\r
366219ab 3931 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {\r
53c71d09 3932 return ARShiftU64 (Op1, (UINTN)Op2);\r
3933 } else {\r
3934 return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));\r
3935 }\r
3936}\r
3937\r
fb0b259e 3938\r
3939/**\r
3940 Execute the EBC EXTNDB instruction to sign-extend a byte value.\r
3941\r
8e3bc754 3942 Instruction syntax:\r
3943 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3944\r
3945 @param VmPtr A pointer to a VM context.\r
fb0b259e 3946 @param Op1 Operand 1 from the instruction\r
3947 @param Op2 Operand 2 from the instruction\r
3948\r
3949 @return (INT64)(INT8)Op2\r
fb0b259e 3950\r
3951**/\r
53c71d09 3952UINT64\r
3953ExecuteEXTNDB (\r
3954 IN VM_CONTEXT *VmPtr,\r
3955 IN UINT64 Op1,\r
3956 IN UINT64 Op2\r
3957 )\r
53c71d09 3958{\r
3959 INT8 Data8;\r
3960 INT64 Data64;\r
3961 //\r
3962 // Convert to byte, then return as 64-bit signed value to let compiler\r
3963 // sign-extend the value\r
3964 //\r
3965 Data8 = (INT8) Op2;\r
3966 Data64 = (INT64) Data8;\r
3967\r
3968 return (UINT64) Data64;\r
3969}\r
3970\r
fb0b259e 3971\r
3972/**\r
3973 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.\r
3974\r
8e3bc754 3975 Instruction syntax:\r
3976 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3977\r
3978 @param VmPtr A pointer to a VM context.\r
fb0b259e 3979 @param Op1 Operand 1 from the instruction\r
3980 @param Op2 Operand 2 from the instruction\r
3981\r
3982 @return (INT64)(INT16)Op2\r
fb0b259e 3983\r
3984**/\r
53c71d09 3985UINT64\r
3986ExecuteEXTNDW (\r
3987 IN VM_CONTEXT *VmPtr,\r
3988 IN UINT64 Op1,\r
3989 IN UINT64 Op2\r
3990 )\r
53c71d09 3991{\r
3992 INT16 Data16;\r
3993 INT64 Data64;\r
3994 //\r
3995 // Convert to word, then return as 64-bit signed value to let compiler\r
3996 // sign-extend the value\r
3997 //\r
3998 Data16 = (INT16) Op2;\r
3999 Data64 = (INT64) Data16;\r
4000\r
4001 return (UINT64) Data64;\r
4002}\r
4003//\r
4004// Execute the EBC EXTNDD instruction.\r
4005//\r
4006// Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]\r
4007// EXTNDD Dest, Source\r
4008//\r
4009// Operation: Dest <- SignExtended((DWORD)Source))\r
4010//\r
fb0b259e 4011\r
4012/**\r
4013 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.\r
4014\r
8e3bc754 4015 Instruction syntax:\r
4016 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
4017\r
4018 @param VmPtr A pointer to a VM context.\r
fb0b259e 4019 @param Op1 Operand 1 from the instruction\r
4020 @param Op2 Operand 2 from the instruction\r
4021\r
4022 @return (INT64)(INT32)Op2\r
fb0b259e 4023\r
4024**/\r
53c71d09 4025UINT64\r
4026ExecuteEXTNDD (\r
4027 IN VM_CONTEXT *VmPtr,\r
4028 IN UINT64 Op1,\r
4029 IN UINT64 Op2\r
4030 )\r
53c71d09 4031{\r
4032 INT32 Data32;\r
4033 INT64 Data64;\r
4034 //\r
4035 // Convert to 32-bit value, then return as 64-bit signed value to let compiler\r
4036 // sign-extend the value\r
4037 //\r
4038 Data32 = (INT32) Op2;\r
4039 Data64 = (INT64) Data32;\r
4040\r
4041 return (UINT64) Data64;\r
4042}\r
4043\r
8e3bc754 4044\r
4045/**\r
4046 Execute all the EBC signed data manipulation instructions.\r
4047 Since the EBC data manipulation instructions all have the same basic form,\r
4048 they can share the code that does the fetch of operands and the write-back\r
4049 of the result. This function performs the fetch of the operands (even if\r
4050 both are not needed to be fetched, like NOT instruction), dispatches to the\r
4051 appropriate subfunction, then writes back the returned result.\r
4052\r
4053 Format:\r
4054 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
4055\r
4056 @param VmPtr A pointer to VM context.\r
4057\r
34e4e297 4058 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 4059 @retval EFI_SUCCESS The instruction is executed successfully.\r
4060\r
4061**/\r
53c71d09 4062EFI_STATUS\r
4063ExecuteSignedDataManip (\r
4064 IN VM_CONTEXT *VmPtr\r
4065 )\r
4066{\r
4067 //\r
4068 // Just call the data manipulation function with a flag indicating this\r
4069 // is a signed operation.\r
4070 //\r
4071 return ExecuteDataManip (VmPtr, TRUE);\r
4072}\r
4073\r
8e3bc754 4074\r
4075/**\r
4076 Execute all the EBC unsigned data manipulation instructions.\r
4077 Since the EBC data manipulation instructions all have the same basic form,\r
4078 they can share the code that does the fetch of operands and the write-back\r
4079 of the result. This function performs the fetch of the operands (even if\r
4080 both are not needed to be fetched, like NOT instruction), dispatches to the\r
4081 appropriate subfunction, then writes back the returned result.\r
4082\r
4083 Format:\r
4084 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
4085\r
4086 @param VmPtr A pointer to VM context.\r
4087\r
34e4e297 4088 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 4089 @retval EFI_SUCCESS The instruction is executed successfully.\r
4090\r
4091**/\r
53c71d09 4092EFI_STATUS\r
4093ExecuteUnsignedDataManip (\r
4094 IN VM_CONTEXT *VmPtr\r
4095 )\r
4096{\r
4097 //\r
4098 // Just call the data manipulation function with a flag indicating this\r
4099 // is not a signed operation.\r
4100 //\r
4101 return ExecuteDataManip (VmPtr, FALSE);\r
4102}\r
4103\r
53c71d09 4104\r
fb0b259e 4105/**\r
4106 Execute all the EBC data manipulation instructions.\r
4107 Since the EBC data manipulation instructions all have the same basic form,\r
53c71d09 4108 they can share the code that does the fetch of operands and the write-back\r
4109 of the result. This function performs the fetch of the operands (even if\r
4110 both are not needed to be fetched, like NOT instruction), dispatches to the\r
4111 appropriate subfunction, then writes back the returned result.\r
4112\r
8e3bc754 4113 Format:\r
4114 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
53c71d09 4115\r
8e3bc754 4116 @param VmPtr A pointer to VM context.\r
4117 @param IsSignedOp Indicates whether the operand is signed or not.\r
4118\r
34e4e297 4119 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 4120 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 4121\r
fb0b259e 4122**/\r
fb0b259e 4123EFI_STATUS\r
4124ExecuteDataManip (\r
4125 IN VM_CONTEXT *VmPtr,\r
4126 IN BOOLEAN IsSignedOp\r
4127 )\r
53c71d09 4128{\r
4129 UINT8 Opcode;\r
4130 INT16 Index16;\r
4131 UINT8 Operands;\r
4132 UINT8 Size;\r
4133 UINT64 Op1;\r
4134 UINT64 Op2;\r
ead7e7dc 4135 INTN DataManipDispatchTableIndex;\r
53c71d09 4136\r
4137 //\r
4138 // Get opcode and operands\r
4139 //\r
4140 Opcode = GETOPCODE (VmPtr);\r
4141 Operands = GETOPERANDS (VmPtr);\r
4142\r
4143 //\r
4144 // Determine if we have immediate data by the opcode\r
4145 //\r
366219ab 4146 if ((Opcode & DATAMANIP_M_IMMDATA) != 0) {\r
53c71d09 4147 //\r
4148 // Index16 if Ry is indirect, or Immed16 if Ry direct.\r
4149 //\r
4150 if (OPERAND2_INDIRECT (Operands)) {\r
4151 Index16 = VmReadIndex16 (VmPtr, 2);\r
4152 } else {\r
4153 Index16 = VmReadImmed16 (VmPtr, 2);\r
4154 }\r
4155\r
4156 Size = 4;\r
4157 } else {\r
4158 Index16 = 0;\r
4159 Size = 2;\r
4160 }\r
4161 //\r
4162 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}\r
4163 //\r
1ccdbf2a 4164 Op2 = (UINT64) VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;\r
53c71d09 4165 if (OPERAND2_INDIRECT (Operands)) {\r
4166 //\r
4167 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data\r
4168 //\r
366219ab 4169 if ((Opcode & DATAMANIP_M_64) != 0) {\r
53c71d09 4170 Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);\r
4171 } else {\r
4172 //\r
4173 // Read as signed value where appropriate.\r
4174 //\r
4175 if (IsSignedOp) {\r
4176 Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));\r
4177 } else {\r
4178 Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);\r
4179 }\r
4180 }\r
4181 } else {\r
4182 if ((Opcode & DATAMANIP_M_64) == 0) {\r
4183 if (IsSignedOp) {\r
4184 Op2 = (UINT64) (INT64) ((INT32) Op2);\r
4185 } else {\r
4186 Op2 = (UINT64) ((UINT32) Op2);\r
4187 }\r
4188 }\r
4189 }\r
4190 //\r
4191 // Get operand1 (destination and sometimes also an actual operand)\r
4192 // of form {@}R1\r
4193 //\r
c9325700 4194 Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];\r
53c71d09 4195 if (OPERAND1_INDIRECT (Operands)) {\r
366219ab 4196 if ((Opcode & DATAMANIP_M_64) != 0) {\r
53c71d09 4197 Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);\r
4198 } else {\r
4199 if (IsSignedOp) {\r
4200 Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));\r
4201 } else {\r
4202 Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);\r
4203 }\r
4204 }\r
4205 } else {\r
4206 if ((Opcode & DATAMANIP_M_64) == 0) {\r
4207 if (IsSignedOp) {\r
4208 Op1 = (UINT64) (INT64) ((INT32) Op1);\r
4209 } else {\r
4210 Op1 = (UINT64) ((UINT32) Op1);\r
4211 }\r
4212 }\r
4213 }\r
4214 //\r
4215 // Dispatch to the computation function\r
4216 //\r
ead7e7dc 4217 DataManipDispatchTableIndex = (Opcode & OPCODE_M_OPCODE) - OPCODE_NOT;\r
4218 if ((DataManipDispatchTableIndex < 0) ||\r
4219 (DataManipDispatchTableIndex >= sizeof (mDataManipDispatchTable) / sizeof (mDataManipDispatchTable[0]))) {\r
53c71d09 4220 EbcDebugSignalException (\r
4221 EXCEPT_EBC_INVALID_OPCODE,\r
4222 EXCEPTION_FLAG_ERROR,\r
4223 VmPtr\r
4224 );\r
4225 //\r
4226 // Advance and return\r
4227 //\r
4228 VmPtr->Ip += Size;\r
4229 return EFI_UNSUPPORTED;\r
4230 } else {\r
ead7e7dc 4231 Op2 = mDataManipDispatchTable[DataManipDispatchTableIndex](VmPtr, Op1, Op2);\r
53c71d09 4232 }\r
4233 //\r
4234 // Write back the result.\r
4235 //\r
4236 if (OPERAND1_INDIRECT (Operands)) {\r
c9325700 4237 Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];\r
366219ab 4238 if ((Opcode & DATAMANIP_M_64) != 0) {\r
53c71d09 4239 VmWriteMem64 (VmPtr, (UINTN) Op1, Op2);\r
4240 } else {\r
4241 VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) Op2);\r
4242 }\r
4243 } else {\r
4244 //\r
4245 // Storage back to a register. Write back, clearing upper bits (as per\r
4246 // the specification) if 32-bit operation.\r
4247 //\r
1ccdbf2a 4248 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;\r
53c71d09 4249 if ((Opcode & DATAMANIP_M_64) == 0) {\r
1ccdbf2a 4250 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF;\r
53c71d09 4251 }\r
4252 }\r
4253 //\r
4254 // Advance the instruction pointer\r
4255 //\r
4256 VmPtr->Ip += Size;\r
4257 return EFI_SUCCESS;\r
4258}\r
4259\r
53c71d09 4260\r
fb0b259e 4261/**\r
8e3bc754 4262 Execute the EBC LOADSP instruction.\r
4263\r
4264 Instruction syntax:\r
4265 LOADSP SP1, R2\r
53c71d09 4266\r
8e3bc754 4267 @param VmPtr A pointer to a VM context.\r
53c71d09 4268\r
34e4e297 4269 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 4270 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 4271\r
fb0b259e 4272**/\r
fb0b259e 4273EFI_STATUS\r
4274ExecuteLOADSP (\r
4275 IN VM_CONTEXT *VmPtr\r
4276 )\r
53c71d09 4277{\r
4278 UINT8 Operands;\r
4279\r
4280 //\r
4281 // Get the operands\r
4282 //\r
4283 Operands = GETOPERANDS (VmPtr);\r
4284\r
4285 //\r
4286 // Do the operation\r
4287 //\r
4288 switch (OPERAND1_REGNUM (Operands)) {\r
4289 //\r
4290 // Set flags\r
4291 //\r
4292 case 0:\r
4293 //\r
4294 // Spec states that this instruction will not modify reserved bits in\r
4295 // the flags register.\r
4296 //\r
1ccdbf2a 4297 VmPtr->Flags = (VmPtr->Flags &~VMFLAGS_ALL_VALID) | (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] & VMFLAGS_ALL_VALID);\r
53c71d09 4298 break;\r
4299\r
4300 default:\r
4301 EbcDebugSignalException (\r
4302 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
4303 EXCEPTION_FLAG_WARNING,\r
4304 VmPtr\r
4305 );\r
4306 VmPtr->Ip += 2;\r
4307 return EFI_UNSUPPORTED;\r
4308 }\r
4309\r
4310 VmPtr->Ip += 2;\r
4311 return EFI_SUCCESS;\r
4312}\r
4313\r
53c71d09 4314\r
fb0b259e 4315/**\r
8e3bc754 4316 Execute the EBC STORESP instruction.\r
53c71d09 4317\r
8e3bc754 4318 Instruction syntax:\r
4319 STORESP Rx, FLAGS|IP\r
53c71d09 4320\r
8e3bc754 4321 @param VmPtr A pointer to a VM context.\r
4322\r
34e4e297 4323 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.\r
8e3bc754 4324 @retval EFI_SUCCESS The instruction is executed successfully.\r
53c71d09 4325\r
fb0b259e 4326**/\r
fb0b259e 4327EFI_STATUS\r
4328ExecuteSTORESP (\r
4329 IN VM_CONTEXT *VmPtr\r
4330 )\r
53c71d09 4331{\r
4332 UINT8 Operands;\r
4333\r
4334 //\r
4335 // Get the operands\r
4336 //\r
4337 Operands = GETOPERANDS (VmPtr);\r
4338\r
4339 //\r
4340 // Do the operation\r
4341 //\r
4342 switch (OPERAND2_REGNUM (Operands)) {\r
4343 //\r
4344 // Get flags\r
4345 //\r
4346 case 0:\r
4347 //\r
4348 // Retrieve the value in the flags register, then clear reserved bits\r
4349 //\r
1ccdbf2a 4350 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID);\r
53c71d09 4351 break;\r
4352\r
4353 //\r
4354 // Get IP -- address of following instruction\r
4355 //\r
4356 case 1:\r
1ccdbf2a 4357 VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (UINTN) VmPtr->Ip + 2;\r
53c71d09 4358 break;\r
4359\r
4360 default:\r
4361 EbcDebugSignalException (\r
4362 EXCEPT_EBC_INSTRUCTION_ENCODING,\r
4363 EXCEPTION_FLAG_WARNING,\r
4364 VmPtr\r
4365 );\r
4366 VmPtr->Ip += 2;\r
4367 return EFI_UNSUPPORTED;\r
4368 break;\r
4369 }\r
4370\r
4371 VmPtr->Ip += 2;\r
4372 return EFI_SUCCESS;\r
4373}\r
4374\r
fb0b259e 4375\r
4376/**\r
4377 Decode a 16-bit index to determine the offset. Given an index value:\r
8e3bc754 4378\r
4379 b15 - sign bit\r
4380 b14:12 - number of bits in this index assigned to natural units (=a)\r
4381 ba:11 - constant units = ConstUnits\r
4382 b0:a - natural units = NaturalUnits\r
34e4e297 4383\r
fb0b259e 4384 Given this info, the offset can be computed by:\r
8e3bc754 4385 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))\r
4386\r
fb0b259e 4387 Max offset is achieved with index = 0x7FFF giving an offset of\r
4388 0x27B (32-bit machine) or 0x477 (64-bit machine).\r
34e4e297 4389 Min offset is achieved with index =\r
fb0b259e 4390\r
8e3bc754 4391 @param VmPtr A pointer to VM context.\r
4392 @param CodeOffset Offset from IP of the location of the 16-bit index\r
4393 to decode.\r
fb0b259e 4394\r
4395 @return The decoded offset.\r
4396\r
4397**/\r
53c71d09 4398INT16\r
4399VmReadIndex16 (\r
4400 IN VM_CONTEXT *VmPtr,\r
4401 IN UINT32 CodeOffset\r
4402 )\r
53c71d09 4403{\r
4404 UINT16 Index;\r
4405 INT16 Offset;\r
8e3bc754 4406 INT16 ConstUnits;\r
4407 INT16 NaturalUnits;\r
53c71d09 4408 INT16 NBits;\r
4409 INT16 Mask;\r
4410\r
4411 //\r
4412 // First read the index from the code stream\r
4413 //\r
4414 Index = VmReadCode16 (VmPtr, CodeOffset);\r
4415\r
4416 //\r
8e3bc754 4417 // Get the mask for NaturalUnits. First get the number of bits from the index.\r
53c71d09 4418 //\r
4419 NBits = (INT16) ((Index & 0x7000) >> 12);\r
4420\r
4421 //\r
4422 // Scale it for 16-bit indexes\r
4423 //\r
4424 NBits *= 2;\r
4425\r
4426 //\r
4427 // Now using the number of bits, create a mask.\r
4428 //\r
4429 Mask = (INT16) ((INT16)~0 << NBits);\r
4430\r
4431 //\r
8e3bc754 4432 // Now using the mask, extract NaturalUnits from the lower bits of the index.\r
53c71d09 4433 //\r
8e3bc754 4434 NaturalUnits = (INT16) (Index &~Mask);\r
53c71d09 4435\r
4436 //\r
8e3bc754 4437 // Now compute ConstUnits\r
53c71d09 4438 //\r
8e3bc754 4439 ConstUnits = (INT16) (((Index &~0xF000) & Mask) >> NBits);\r
53c71d09 4440\r
8e3bc754 4441 Offset = (INT16) (NaturalUnits * sizeof (UINTN) + ConstUnits);\r
53c71d09 4442\r
4443 //\r
4444 // Now set the sign\r
4445 //\r
366219ab 4446 if ((Index & 0x8000) != 0) {\r
53c71d09 4447 //\r
4448 // Do it the hard way to work around a bogus compiler warning\r
4449 //\r
4450 // Offset = -1 * Offset;\r
4451 //\r
4452 Offset = (INT16) ((INT32) Offset * -1);\r
4453 }\r
4454\r
4455 return Offset;\r
4456}\r
4457\r
fb0b259e 4458\r
4459/**\r
4460 Decode a 32-bit index to determine the offset.\r
4461\r
8e3bc754 4462 @param VmPtr A pointer to VM context.\r
4463 @param CodeOffset Offset from IP of the location of the 32-bit index\r
4464 to decode.\r
fb0b259e 4465\r
8e3bc754 4466 @return Converted index per EBC VM specification.\r
fb0b259e 4467\r
4468**/\r
53c71d09 4469INT32\r
4470VmReadIndex32 (\r
4471 IN VM_CONTEXT *VmPtr,\r
4472 IN UINT32 CodeOffset\r
4473 )\r
53c71d09 4474{\r
4475 UINT32 Index;\r
4476 INT32 Offset;\r
8e3bc754 4477 INT32 ConstUnits;\r
4478 INT32 NaturalUnits;\r
53c71d09 4479 INT32 NBits;\r
4480 INT32 Mask;\r
4481\r
4482 Index = VmReadImmed32 (VmPtr, CodeOffset);\r
4483\r
4484 //\r
8e3bc754 4485 // Get the mask for NaturalUnits. First get the number of bits from the index.\r
53c71d09 4486 //\r
4487 NBits = (Index & 0x70000000) >> 28;\r
4488\r
4489 //\r
4490 // Scale it for 32-bit indexes\r
4491 //\r
4492 NBits *= 4;\r
4493\r
4494 //\r
4495 // Now using the number of bits, create a mask.\r
4496 //\r
4497 Mask = (INT32)~0 << NBits;\r
4498\r
4499 //\r
8e3bc754 4500 // Now using the mask, extract NaturalUnits from the lower bits of the index.\r
53c71d09 4501 //\r
8e3bc754 4502 NaturalUnits = Index &~Mask;\r
53c71d09 4503\r
4504 //\r
8e3bc754 4505 // Now compute ConstUnits\r
53c71d09 4506 //\r
8e3bc754 4507 ConstUnits = ((Index &~0xF0000000) & Mask) >> NBits;\r
53c71d09 4508\r
8e3bc754 4509 Offset = NaturalUnits * sizeof (UINTN) + ConstUnits;\r
53c71d09 4510\r
4511 //\r
4512 // Now set the sign\r
4513 //\r
366219ab 4514 if ((Index & 0x80000000) != 0) {\r
53c71d09 4515 Offset = Offset * -1;\r
4516 }\r
4517\r
4518 return Offset;\r
4519}\r
4520\r
fb0b259e 4521\r
4522/**\r
4523 Decode a 64-bit index to determine the offset.\r
4524\r
8e3bc754 4525 @param VmPtr A pointer to VM context.s\r
4526 @param CodeOffset Offset from IP of the location of the 64-bit index\r
4527 to decode.\r
fb0b259e 4528\r
4529 @return Converted index per EBC VM specification\r
4530\r
4531**/\r
53c71d09 4532INT64\r
4533VmReadIndex64 (\r
4534 IN VM_CONTEXT *VmPtr,\r
4535 IN UINT32 CodeOffset\r
4536 )\r
53c71d09 4537{\r
4538 UINT64 Index;\r
4539 INT64 Offset;\r
8e3bc754 4540 INT64 ConstUnits;\r
4541 INT64 NaturalUnits;\r
53c71d09 4542 INT64 NBits;\r
4543 INT64 Mask;\r
4544\r
4545 Index = VmReadCode64 (VmPtr, CodeOffset);\r
4546\r
4547 //\r
8e3bc754 4548 // Get the mask for NaturalUnits. First get the number of bits from the index.\r
53c71d09 4549 //\r
4550 NBits = RShiftU64 ((Index & 0x7000000000000000ULL), 60);\r
4551\r
4552 //\r
4553 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)\r
4554 //\r
4555 NBits = LShiftU64 ((UINT64)NBits, 3);\r
4556\r
4557 //\r
4558 // Now using the number of bits, create a mask.\r
4559 //\r
4560 Mask = (LShiftU64 ((UINT64)~0, (UINTN)NBits));\r
4561\r
4562 //\r
8e3bc754 4563 // Now using the mask, extract NaturalUnits from the lower bits of the index.\r
53c71d09 4564 //\r
8e3bc754 4565 NaturalUnits = Index &~Mask;\r
53c71d09 4566\r
4567 //\r
8e3bc754 4568 // Now compute ConstUnits\r
53c71d09 4569 //\r
8e3bc754 4570 ConstUnits = ARShiftU64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN)NBits);\r
53c71d09 4571\r
c9325700 4572 Offset = MultU64x64 ((UINT64) NaturalUnits, sizeof (UINTN)) + ConstUnits;\r
53c71d09 4573\r
4574 //\r
4575 // Now set the sign\r
4576 //\r
366219ab 4577 if ((Index & 0x8000000000000000ULL) != 0) {\r
53c71d09 4578 Offset = MultS64x64 (Offset, -1);\r
4579 }\r
4580\r
4581 return Offset;\r
4582}\r
4583\r
53c71d09 4584\r
fb0b259e 4585/**\r
8e3bc754 4586 Writes 8-bit data to memory address.\r
34e4e297 4587\r
8e3bc754 4588 This routine is called by the EBC data\r
53c71d09 4589 movement instructions that write to memory. Since these writes\r
4590 may be to the stack, which looks like (high address on top) this,\r
8e3bc754 4591\r
53c71d09 4592 [EBC entry point arguments]\r
4593 [VM stack]\r
4594 [EBC stack]\r
8e3bc754 4595\r
53c71d09 4596 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 4597 stack area and adjust the address (which will initially point into the\r
53c71d09 4598 VM stack) to point into the EBC entry point arguments.\r
4599\r
8e3bc754 4600 @param VmPtr A pointer to a VM context.\r
48557c65 4601 @param Addr Address to write to.\r
8e3bc754 4602 @param Data Value to write to Addr.\r
fb0b259e 4603\r
34e4e297 4604 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 4605 @retval Other Some error occurs when writing data to the address.\r
53c71d09 4606\r
fb0b259e 4607**/\r
fb0b259e 4608EFI_STATUS\r
4609VmWriteMem8 (\r
4610 IN VM_CONTEXT *VmPtr,\r
4611 IN UINTN Addr,\r
4612 IN UINT8 Data\r
4613 )\r
53c71d09 4614{\r
4615 //\r
4616 // Convert the address if it's in the stack gap\r
4617 //\r
4618 Addr = ConvertStackAddr (VmPtr, Addr);\r
4619 *(UINT8 *) Addr = Data;\r
4620 return EFI_SUCCESS;\r
4621}\r
4622\r
8e3bc754 4623/**\r
4624 Writes 16-bit data to memory address.\r
34e4e297 4625\r
8e3bc754 4626 This routine is called by the EBC data\r
4627 movement instructions that write to memory. Since these writes\r
4628 may be to the stack, which looks like (high address on top) this,\r
4629\r
4630 [EBC entry point arguments]\r
4631 [VM stack]\r
4632 [EBC stack]\r
4633\r
4634 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 4635 stack area and adjust the address (which will initially point into the\r
8e3bc754 4636 VM stack) to point into the EBC entry point arguments.\r
4637\r
4638 @param VmPtr A pointer to a VM context.\r
48557c65 4639 @param Addr Address to write to.\r
8e3bc754 4640 @param Data Value to write to Addr.\r
4641\r
34e4e297 4642 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 4643 @retval Other Some error occurs when writing data to the address.\r
4644\r
4645**/\r
53c71d09 4646EFI_STATUS\r
4647VmWriteMem16 (\r
4648 IN VM_CONTEXT *VmPtr,\r
4649 IN UINTN Addr,\r
4650 IN UINT16 Data\r
4651 )\r
4652{\r
4653 EFI_STATUS Status;\r
4654\r
4655 //\r
4656 // Convert the address if it's in the stack gap\r
4657 //\r
4658 Addr = ConvertStackAddr (VmPtr, Addr);\r
4659\r
4660 //\r
4661 // Do a simple write if aligned\r
4662 //\r
4663 if (IS_ALIGNED (Addr, sizeof (UINT16))) {\r
4664 *(UINT16 *) Addr = Data;\r
4665 } else {\r
4666 //\r
4667 // Write as two bytes\r
4668 //\r
4669 MemoryFence ();\r
4670 if ((Status = VmWriteMem8 (VmPtr, Addr, (UINT8) Data)) != EFI_SUCCESS) {\r
4671 return Status;\r
4672 }\r
4673\r
4674 MemoryFence ();\r
4675 if ((Status = VmWriteMem8 (VmPtr, Addr + 1, (UINT8) (Data >> 8))) != EFI_SUCCESS) {\r
4676 return Status;\r
4677 }\r
4678\r
4679 MemoryFence ();\r
4680 }\r
4681\r
4682 return EFI_SUCCESS;\r
4683}\r
4684\r
8e3bc754 4685\r
4686/**\r
4687 Writes 32-bit data to memory address.\r
34e4e297 4688\r
8e3bc754 4689 This routine is called by the EBC data\r
4690 movement instructions that write to memory. Since these writes\r
4691 may be to the stack, which looks like (high address on top) this,\r
4692\r
4693 [EBC entry point arguments]\r
4694 [VM stack]\r
4695 [EBC stack]\r
4696\r
4697 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 4698 stack area and adjust the address (which will initially point into the\r
8e3bc754 4699 VM stack) to point into the EBC entry point arguments.\r
4700\r
4701 @param VmPtr A pointer to a VM context.\r
48557c65 4702 @param Addr Address to write to.\r
8e3bc754 4703 @param Data Value to write to Addr.\r
4704\r
34e4e297 4705 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 4706 @retval Other Some error occurs when writing data to the address.\r
4707\r
4708**/\r
53c71d09 4709EFI_STATUS\r
4710VmWriteMem32 (\r
4711 IN VM_CONTEXT *VmPtr,\r
4712 IN UINTN Addr,\r
4713 IN UINT32 Data\r
4714 )\r
4715{\r
4716 EFI_STATUS Status;\r
4717\r
4718 //\r
4719 // Convert the address if it's in the stack gap\r
4720 //\r
4721 Addr = ConvertStackAddr (VmPtr, Addr);\r
4722\r
4723 //\r
4724 // Do a simple write if aligned\r
4725 //\r
4726 if (IS_ALIGNED (Addr, sizeof (UINT32))) {\r
4727 *(UINT32 *) Addr = Data;\r
4728 } else {\r
4729 //\r
4730 // Write as two words\r
4731 //\r
4732 MemoryFence ();\r
4733 if ((Status = VmWriteMem16 (VmPtr, Addr, (UINT16) Data)) != EFI_SUCCESS) {\r
4734 return Status;\r
4735 }\r
4736\r
4737 MemoryFence ();\r
4738 if ((Status = VmWriteMem16 (VmPtr, Addr + sizeof (UINT16), (UINT16) (Data >> 16))) != EFI_SUCCESS) {\r
4739 return Status;\r
4740 }\r
4741\r
4742 MemoryFence ();\r
4743 }\r
4744\r
4745 return EFI_SUCCESS;\r
4746}\r
4747\r
8e3bc754 4748\r
4749/**\r
4750 Writes 64-bit data to memory address.\r
34e4e297 4751\r
8e3bc754 4752 This routine is called by the EBC data\r
4753 movement instructions that write to memory. Since these writes\r
4754 may be to the stack, which looks like (high address on top) this,\r
4755\r
4756 [EBC entry point arguments]\r
4757 [VM stack]\r
4758 [EBC stack]\r
4759\r
4760 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 4761 stack area and adjust the address (which will initially point into the\r
8e3bc754 4762 VM stack) to point into the EBC entry point arguments.\r
4763\r
4764 @param VmPtr A pointer to a VM context.\r
48557c65 4765 @param Addr Address to write to.\r
8e3bc754 4766 @param Data Value to write to Addr.\r
4767\r
34e4e297 4768 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 4769 @retval Other Some error occurs when writing data to the address.\r
4770\r
4771**/\r
53c71d09 4772EFI_STATUS\r
4773VmWriteMem64 (\r
4774 IN VM_CONTEXT *VmPtr,\r
4775 IN UINTN Addr,\r
4776 IN UINT64 Data\r
4777 )\r
4778{\r
4779 EFI_STATUS Status;\r
53c71d09 4780\r
4781 //\r
4782 // Convert the address if it's in the stack gap\r
4783 //\r
4784 Addr = ConvertStackAddr (VmPtr, Addr);\r
4785\r
4786 //\r
4787 // Do a simple write if aligned\r
4788 //\r
4789 if (IS_ALIGNED (Addr, sizeof (UINT64))) {\r
4790 *(UINT64 *) Addr = Data;\r
4791 } else {\r
4792 //\r
4793 // Write as two 32-bit words\r
4794 //\r
4795 MemoryFence ();\r
4796 if ((Status = VmWriteMem32 (VmPtr, Addr, (UINT32) Data)) != EFI_SUCCESS) {\r
4797 return Status;\r
4798 }\r
4799\r
4800 MemoryFence ();\r
c9325700 4801 if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), (UINT32) RShiftU64(Data, 32))) != EFI_SUCCESS) {\r
53c71d09 4802 return Status;\r
4803 }\r
4804\r
4805 MemoryFence ();\r
4806 }\r
4807\r
4808 return EFI_SUCCESS;\r
4809}\r
4810\r
8e3bc754 4811\r
4812/**\r
4813 Writes UINTN data to memory address.\r
34e4e297 4814\r
8e3bc754 4815 This routine is called by the EBC data\r
4816 movement instructions that write to memory. Since these writes\r
4817 may be to the stack, which looks like (high address on top) this,\r
4818\r
4819 [EBC entry point arguments]\r
4820 [VM stack]\r
4821 [EBC stack]\r
4822\r
4823 we need to detect all attempts to write to the EBC entry point argument\r
34e4e297 4824 stack area and adjust the address (which will initially point into the\r
8e3bc754 4825 VM stack) to point into the EBC entry point arguments.\r
4826\r
4827 @param VmPtr A pointer to a VM context.\r
48557c65 4828 @param Addr Address to write to.\r
8e3bc754 4829 @param Data Value to write to Addr.\r
4830\r
34e4e297 4831 @retval EFI_SUCCESS The instruction is executed successfully.\r
8e3bc754 4832 @retval Other Some error occurs when writing data to the address.\r
4833\r
4834**/\r
53c71d09 4835EFI_STATUS\r
4836VmWriteMemN (\r
4837 IN VM_CONTEXT *VmPtr,\r
4838 IN UINTN Addr,\r
4839 IN UINTN Data\r
4840 )\r
4841{\r
4842 EFI_STATUS Status;\r
4843 UINTN Index;\r
4844\r
4845 Status = EFI_SUCCESS;\r
4846\r
4847 //\r
4848 // Convert the address if it's in the stack gap\r
4849 //\r
4850 Addr = ConvertStackAddr (VmPtr, Addr);\r
4851\r
4852 //\r
4853 // Do a simple write if aligned\r
4854 //\r
4855 if (IS_ALIGNED (Addr, sizeof (UINTN))) {\r
4856 *(UINTN *) Addr = Data;\r
4857 } else {\r
4858 for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {\r
4859 MemoryFence ();\r
4860 Status = VmWriteMem32 (VmPtr, Addr + Index * sizeof (UINT32), (UINT32) Data);\r
4861 MemoryFence ();\r
34e4e297 4862 Data = (UINTN) RShiftU64 ((UINT64)Data, 32);\r
53c71d09 4863 }\r
4864 }\r
4865\r
4866 return Status;\r
4867}\r
4868\r
53c71d09 4869\r
fb0b259e 4870/**\r
8e3bc754 4871 Reads 8-bit immediate value at the offset.\r
4872\r
4873 This routine is called by the EBC execute\r
53c71d09 4874 functions to read EBC immediate values from the code stream.\r
fb0b259e 4875 Since we can't assume alignment, each tries to read in the biggest\r
53c71d09 4876 chunks size available, but will revert to smaller reads if necessary.\r
4877\r
8e3bc754 4878 @param VmPtr A pointer to a VM context.\r
fb0b259e 4879 @param Offset offset from IP of the code bytes to read.\r
53c71d09 4880\r
fb0b259e 4881 @return Signed data of the requested size from the specified address.\r
53c71d09 4882\r
fb0b259e 4883**/\r
fb0b259e 4884INT8\r
4885VmReadImmed8 (\r
4886 IN VM_CONTEXT *VmPtr,\r
4887 IN UINT32 Offset\r
4888 )\r
53c71d09 4889{\r
4890 //\r
4891 // Simply return the data in flat memory space\r
4892 //\r
4893 return * (INT8 *) (VmPtr->Ip + Offset);\r
4894}\r
4895\r
8e3bc754 4896/**\r
4897 Reads 16-bit immediate value at the offset.\r
4898\r
4899 This routine is called by the EBC execute\r
4900 functions to read EBC immediate values from the code stream.\r
4901 Since we can't assume alignment, each tries to read in the biggest\r
4902 chunks size available, but will revert to smaller reads if necessary.\r
4903\r
4904 @param VmPtr A pointer to a VM context.\r
4905 @param Offset offset from IP of the code bytes to read.\r
4906\r
4907 @return Signed data of the requested size from the specified address.\r
4908\r
4909**/\r
53c71d09 4910INT16\r
4911VmReadImmed16 (\r
4912 IN VM_CONTEXT *VmPtr,\r
4913 IN UINT32 Offset\r
4914 )\r
4915{\r
4916 //\r
4917 // Read direct if aligned\r
4918 //\r
4919 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {\r
4920 return * (INT16 *) (VmPtr->Ip + Offset);\r
4921 } else {\r
4922 //\r
4923 // All code word reads should be aligned\r
4924 //\r
4925 EbcDebugSignalException (\r
4926 EXCEPT_EBC_ALIGNMENT_CHECK,\r
4927 EXCEPTION_FLAG_WARNING,\r
4928 VmPtr\r
4929 );\r
4930 }\r
4931 //\r
4932 // Return unaligned data\r
4933 //\r
4934 return (INT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));\r
4935}\r
4936\r
8e3bc754 4937\r
4938/**\r
4939 Reads 32-bit immediate value at the offset.\r
4940\r
4941 This routine is called by the EBC execute\r
4942 functions to read EBC immediate values from the code stream.\r
4943 Since we can't assume alignment, each tries to read in the biggest\r
4944 chunks size available, but will revert to smaller reads if necessary.\r
4945\r
4946 @param VmPtr A pointer to a VM context.\r
4947 @param Offset offset from IP of the code bytes to read.\r
4948\r
4949 @return Signed data of the requested size from the specified address.\r
4950\r
4951**/\r
53c71d09 4952INT32\r
4953VmReadImmed32 (\r
4954 IN VM_CONTEXT *VmPtr,\r
4955 IN UINT32 Offset\r
4956 )\r
4957{\r
4958 UINT32 Data;\r
4959\r
4960 //\r
4961 // Read direct if aligned\r
4962 //\r
4963 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {\r
4964 return * (INT32 *) (VmPtr->Ip + Offset);\r
4965 }\r
4966 //\r
4967 // Return unaligned data\r
4968 //\r
34e4e297 4969 Data = (UINT32) VmReadCode16 (VmPtr, Offset);\r
4970 Data |= (UINT32)(VmReadCode16 (VmPtr, Offset + 2) << 16);\r
53c71d09 4971 return Data;\r
4972}\r
4973\r
8e3bc754 4974\r
4975/**\r
4976 Reads 64-bit immediate value at the offset.\r
4977\r
4978 This routine is called by the EBC execute\r
4979 functions to read EBC immediate values from the code stream.\r
4980 Since we can't assume alignment, each tries to read in the biggest\r
4981 chunks size available, but will revert to smaller reads if necessary.\r
4982\r
4983 @param VmPtr A pointer to a VM context.\r
4984 @param Offset offset from IP of the code bytes to read.\r
4985\r
4986 @return Signed data of the requested size from the specified address.\r
4987\r
4988**/\r
53c71d09 4989INT64\r
4990VmReadImmed64 (\r
4991 IN VM_CONTEXT *VmPtr,\r
4992 IN UINT32 Offset\r
4993 )\r
4994{\r
4995 UINT64 Data64;\r
4996 UINT32 Data32;\r
4997 UINT8 *Ptr;\r
4998\r
4999 //\r
5000 // Read direct if aligned\r
5001 //\r
5002 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {\r
5003 return * (UINT64 *) (VmPtr->Ip + Offset);\r
5004 }\r
5005 //\r
5006 // Return unaligned data.\r
5007 //\r
5008 Ptr = (UINT8 *) &Data64;\r
5009 Data32 = VmReadCode32 (VmPtr, Offset);\r
5010 *(UINT32 *) Ptr = Data32;\r
34e4e297 5011 Ptr += sizeof (Data32);\r
53c71d09 5012 Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));\r
5013 *(UINT32 *) Ptr = Data32;\r
5014 return Data64;\r
5015}\r
5016\r
fb0b259e 5017\r
5018/**\r
48557c65 5019 Reads 16-bit unsigned data from the code stream.\r
8e3bc754 5020\r
5021 This routine provides the ability to read raw unsigned data from the code\r
5022 stream.\r
fb0b259e 5023\r
8e3bc754 5024 @param VmPtr A pointer to VM context\r
5025 @param Offset Offset from current IP to the raw data to read.\r
fb0b259e 5026\r
5027 @return The raw unsigned 16-bit value from the code stream.\r
5028\r
5029**/\r
53c71d09 5030UINT16\r
5031VmReadCode16 (\r
5032 IN VM_CONTEXT *VmPtr,\r
5033 IN UINT32 Offset\r
5034 )\r
53c71d09 5035{\r
5036 //\r
5037 // Read direct if aligned\r
5038 //\r
5039 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {\r
5040 return * (UINT16 *) (VmPtr->Ip + Offset);\r
5041 } else {\r
5042 //\r
5043 // All code word reads should be aligned\r
5044 //\r
5045 EbcDebugSignalException (\r
5046 EXCEPT_EBC_ALIGNMENT_CHECK,\r
5047 EXCEPTION_FLAG_WARNING,\r
5048 VmPtr\r
5049 );\r
5050 }\r
5051 //\r
5052 // Return unaligned data\r
5053 //\r
5054 return (UINT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));\r
5055}\r
5056\r
8e3bc754 5057\r
5058/**\r
48557c65 5059 Reads 32-bit unsigned data from the code stream.\r
8e3bc754 5060\r
5061 This routine provides the ability to read raw unsigned data from the code\r
5062 stream.\r
5063\r
5064 @param VmPtr A pointer to VM context\r
5065 @param Offset Offset from current IP to the raw data to read.\r
5066\r
5067 @return The raw unsigned 32-bit value from the code stream.\r
5068\r
5069**/\r
53c71d09 5070UINT32\r
5071VmReadCode32 (\r
5072 IN VM_CONTEXT *VmPtr,\r
5073 IN UINT32 Offset\r
5074 )\r
5075{\r
5076 UINT32 Data;\r
5077 //\r
5078 // Read direct if aligned\r
5079 //\r
5080 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {\r
5081 return * (UINT32 *) (VmPtr->Ip + Offset);\r
5082 }\r
5083 //\r
5084 // Return unaligned data\r
5085 //\r
5086 Data = (UINT32) VmReadCode16 (VmPtr, Offset);\r
5087 Data |= (VmReadCode16 (VmPtr, Offset + 2) << 16);\r
5088 return Data;\r
5089}\r
5090\r
8e3bc754 5091\r
5092/**\r
48557c65 5093 Reads 64-bit unsigned data from the code stream.\r
8e3bc754 5094\r
5095 This routine provides the ability to read raw unsigned data from the code\r
5096 stream.\r
5097\r
5098 @param VmPtr A pointer to VM context\r
5099 @param Offset Offset from current IP to the raw data to read.\r
5100\r
5101 @return The raw unsigned 64-bit value from the code stream.\r
5102\r
5103**/\r
53c71d09 5104UINT64\r
5105VmReadCode64 (\r
5106 IN VM_CONTEXT *VmPtr,\r
5107 IN UINT32 Offset\r
5108 )\r
5109{\r
5110 UINT64 Data64;\r
5111 UINT32 Data32;\r
5112 UINT8 *Ptr;\r
5113\r
5114 //\r
5115 // Read direct if aligned\r
5116 //\r
5117 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {\r
5118 return * (UINT64 *) (VmPtr->Ip + Offset);\r
5119 }\r
5120 //\r
5121 // Return unaligned data.\r
5122 //\r
5123 Ptr = (UINT8 *) &Data64;\r
5124 Data32 = VmReadCode32 (VmPtr, Offset);\r
5125 *(UINT32 *) Ptr = Data32;\r
34e4e297 5126 Ptr += sizeof (Data32);\r
53c71d09 5127 Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));\r
5128 *(UINT32 *) Ptr = Data32;\r
5129 return Data64;\r
5130}\r
5131\r
8e3bc754 5132\r
5133/**\r
5134 Reads 8-bit data form the memory address.\r
5135\r
5136 @param VmPtr A pointer to VM context.\r
5137 @param Addr The memory address.\r
5138\r
48557c65 5139 @return The 8-bit value from the memory address.\r
8e3bc754 5140\r
5141**/\r
53c71d09 5142UINT8\r
5143VmReadMem8 (\r
5144 IN VM_CONTEXT *VmPtr,\r
5145 IN UINTN Addr\r
5146 )\r
5147{\r
5148 //\r
5149 // Convert the address if it's in the stack gap\r
5150 //\r
5151 Addr = ConvertStackAddr (VmPtr, Addr);\r
5152 //\r
5153 // Simply return the data in flat memory space\r
5154 //\r
5155 return * (UINT8 *) Addr;\r
5156}\r
5157\r
8e3bc754 5158/**\r
5159 Reads 16-bit data form the memory address.\r
5160\r
5161 @param VmPtr A pointer to VM context.\r
5162 @param Addr The memory address.\r
5163\r
48557c65 5164 @return The 16-bit value from the memory address.\r
8e3bc754 5165\r
5166**/\r
53c71d09 5167UINT16\r
5168VmReadMem16 (\r
5169 IN VM_CONTEXT *VmPtr,\r
5170 IN UINTN Addr\r
5171 )\r
5172{\r
5173 //\r
5174 // Convert the address if it's in the stack gap\r
5175 //\r
5176 Addr = ConvertStackAddr (VmPtr, Addr);\r
5177 //\r
5178 // Read direct if aligned\r
5179 //\r
5180 if (IS_ALIGNED (Addr, sizeof (UINT16))) {\r
5181 return * (UINT16 *) Addr;\r
5182 }\r
5183 //\r
5184 // Return unaligned data\r
5185 //\r
5186 return (UINT16) (*(UINT8 *) Addr + (*(UINT8 *) (Addr + 1) << 8));\r
5187}\r
5188\r
8e3bc754 5189/**\r
5190 Reads 32-bit data form the memory address.\r
5191\r
5192 @param VmPtr A pointer to VM context.\r
5193 @param Addr The memory address.\r
5194\r
48557c65 5195 @return The 32-bit value from the memory address.\r
8e3bc754 5196\r
5197**/\r
53c71d09 5198UINT32\r
5199VmReadMem32 (\r
5200 IN VM_CONTEXT *VmPtr,\r
5201 IN UINTN Addr\r
5202 )\r
5203{\r
5204 UINT32 Data;\r
5205\r
5206 //\r
5207 // Convert the address if it's in the stack gap\r
5208 //\r
5209 Addr = ConvertStackAddr (VmPtr, Addr);\r
5210 //\r
5211 // Read direct if aligned\r
5212 //\r
5213 if (IS_ALIGNED (Addr, sizeof (UINT32))) {\r
5214 return * (UINT32 *) Addr;\r
5215 }\r
5216 //\r
5217 // Return unaligned data\r
5218 //\r
5219 Data = (UINT32) VmReadMem16 (VmPtr, Addr);\r
5220 Data |= (VmReadMem16 (VmPtr, Addr + 2) << 16);\r
5221 return Data;\r
5222}\r
5223\r
8e3bc754 5224/**\r
5225 Reads 64-bit data form the memory address.\r
5226\r
5227 @param VmPtr A pointer to VM context.\r
5228 @param Addr The memory address.\r
5229\r
48557c65 5230 @return The 64-bit value from the memory address.\r
8e3bc754 5231\r
5232**/\r
53c71d09 5233UINT64\r
5234VmReadMem64 (\r
5235 IN VM_CONTEXT *VmPtr,\r
5236 IN UINTN Addr\r
5237 )\r
5238{\r
5239 UINT64 Data;\r
5240 UINT32 Data32;\r
5241\r
5242 //\r
5243 // Convert the address if it's in the stack gap\r
5244 //\r
5245 Addr = ConvertStackAddr (VmPtr, Addr);\r
5246\r
5247 //\r
5248 // Read direct if aligned\r
5249 //\r
5250 if (IS_ALIGNED (Addr, sizeof (UINT64))) {\r
5251 return * (UINT64 *) Addr;\r
5252 }\r
5253 //\r
5254 // Return unaligned data. Assume little endian.\r
5255 //\r
c9325700
ED
5256 Data32 = VmReadMem32 (VmPtr, Addr);\r
5257 Data = (UINT64) VmReadMem32 (VmPtr, Addr + sizeof (UINT32));\r
5258 Data = LShiftU64 (Data, 32) | Data32;\r
53c71d09 5259 return Data;\r
5260}\r
5261\r
53c71d09 5262\r
fb0b259e 5263/**\r
53c71d09 5264 Given an address that EBC is going to read from or write to, return\r
5265 an appropriate address that accounts for a gap in the stack.\r
53c71d09 5266 The stack for this application looks like this (high addr on top)\r
5267 [EBC entry point arguments]\r
5268 [VM stack]\r
5269 [EBC stack]\r
53c71d09 5270 The EBC assumes that its arguments are at the top of its stack, which\r
5271 is where the VM stack is really. Therefore if the EBC does memory\r
5272 accesses into the VM stack area, then we need to convert the address\r
5273 to point to the EBC entry point arguments area. Do this here.\r
5274\r
8e3bc754 5275 @param VmPtr A Pointer to VM context.\r
5276 @param Addr Address of interest\r
53c71d09 5277\r
fb0b259e 5278 @return The unchanged address if it's not in the VM stack region. Otherwise,\r
8e3bc754 5279 adjust for the stack gap and return the modified address.\r
53c71d09 5280\r
fb0b259e 5281**/\r
fb0b259e 5282UINTN\r
5283ConvertStackAddr (\r
5284 IN VM_CONTEXT *VmPtr,\r
5285 IN UINTN Addr\r
5286 )\r
5287{\r
53c71d09 5288 ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));\r
5289 return Addr;\r
5290}\r
5291\r
fb0b259e 5292\r
5293/**\r
5294 Read a natural value from memory. May or may not be aligned.\r
5295\r
5296 @param VmPtr current VM context\r
5297 @param Addr the address to read from\r
5298\r
5299 @return The natural value at address Addr.\r
5300\r
5301**/\r
53c71d09 5302UINTN\r
5303VmReadMemN (\r
5304 IN VM_CONTEXT *VmPtr,\r
5305 IN UINTN Addr\r
5306 )\r
53c71d09 5307{\r
5308 UINTN Data;\r
5309 volatile UINT32 Size;\r
5310 UINT8 *FromPtr;\r
5311 UINT8 *ToPtr;\r
5312 //\r
5313 // Convert the address if it's in the stack gap\r
5314 //\r
5315 Addr = ConvertStackAddr (VmPtr, Addr);\r
5316 //\r
5317 // Read direct if aligned\r
5318 //\r
5319 if (IS_ALIGNED (Addr, sizeof (UINTN))) {\r
5320 return * (UINTN *) Addr;\r
5321 }\r
5322 //\r
5323 // Return unaligned data\r
5324 //\r
5325 Data = 0;\r
5326 FromPtr = (UINT8 *) Addr;\r
5327 ToPtr = (UINT8 *) &Data;\r
5328\r
5329 for (Size = 0; Size < sizeof (Data); Size++) {\r
5330 *ToPtr = *FromPtr;\r
5331 ToPtr++;\r
5332 FromPtr++;\r
5333 }\r
5334\r
5335 return Data;\r
5336}\r
5337\r
8e3bc754 5338/**\r
5339 Returns the version of the EBC virtual machine.\r
34e4e297 5340\r
8e3bc754 5341 @return The 64-bit version of EBC virtual machine.\r
5342\r
5343**/\r
53c71d09 5344UINT64\r
5345GetVmVersion (\r
5346 VOID\r
5347 )\r
5348{\r
5349 return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)));\r
5350}\r