174e774de3087d81f3be5529346f88093b5ca1a7
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / EbcDxe / EbcExecute.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   EbcExecute.c\r
15 \r
16 Abstract:\r
17 \r
18   Contains code that implements the virtual machine.\r
19 \r
20 --*/\r
21 \r
22 #include "EbcInt.h"\r
23 #include "EbcExecute.h"\r
24 \r
25 \r
26 //\r
27 // Define some useful data size constants to allow switch statements based on\r
28 // size of operands or data.\r
29 //\r
30 #define DATA_SIZE_INVALID 0\r
31 #define DATA_SIZE_8       1\r
32 #define DATA_SIZE_16      2\r
33 #define DATA_SIZE_32      4\r
34 #define DATA_SIZE_64      8\r
35 #define DATA_SIZE_N       48  // 4 or 8\r
36 //\r
37 // Structure we'll use to dispatch opcodes to execute functions.\r
38 //\r
39 typedef struct {\r
40   EFI_STATUS (*ExecuteFunction) (IN VM_CONTEXT * VmPtr);\r
41 }\r
42 VM_TABLE_ENTRY;\r
43 \r
44 typedef\r
45 UINT64\r
46 (*DATA_MANIP_EXEC_FUNCTION) (\r
47   IN VM_CONTEXT * VmPtr,\r
48   IN UINT64     Op1,\r
49   IN UINT64     Op2\r
50   );\r
51 \r
52 STATIC\r
53 INT16\r
54 VmReadIndex16 (\r
55   IN VM_CONTEXT *VmPtr,\r
56   IN UINT32     CodeOffset\r
57   );\r
58 \r
59 STATIC\r
60 INT32\r
61 VmReadIndex32 (\r
62   IN VM_CONTEXT *VmPtr,\r
63   IN UINT32     CodeOffset\r
64   );\r
65 \r
66 STATIC\r
67 INT64\r
68 VmReadIndex64 (\r
69   IN VM_CONTEXT *VmPtr,\r
70   IN UINT32     CodeOffset\r
71   );\r
72 \r
73 STATIC\r
74 UINT8\r
75 VmReadMem8 (\r
76   IN VM_CONTEXT *VmPtr,\r
77   IN UINTN      Addr\r
78   );\r
79 \r
80 STATIC\r
81 UINT16\r
82 VmReadMem16 (\r
83   IN VM_CONTEXT *VmPtr,\r
84   IN UINTN      Addr\r
85   );\r
86 \r
87 STATIC\r
88 UINT32\r
89 VmReadMem32 (\r
90   IN VM_CONTEXT *VmPtr,\r
91   IN UINTN      Addr\r
92   );\r
93 \r
94 STATIC\r
95 UINT64\r
96 VmReadMem64 (\r
97   IN VM_CONTEXT *VmPtr,\r
98   IN UINTN      Addr\r
99   );\r
100 \r
101 STATIC\r
102 UINTN\r
103 VmReadMemN (\r
104   IN VM_CONTEXT *VmPtr,\r
105   IN UINTN      Addr\r
106   );\r
107 \r
108 STATIC\r
109 EFI_STATUS\r
110 VmWriteMem8 (\r
111   IN VM_CONTEXT *VmPtr,\r
112   UINTN         Addr,\r
113   IN UINT8      Data\r
114   );\r
115 \r
116 STATIC\r
117 EFI_STATUS\r
118 VmWriteMem16 (\r
119   IN VM_CONTEXT *VmPtr,\r
120   UINTN         Addr,\r
121   IN UINT16     Data\r
122   );\r
123 \r
124 STATIC\r
125 EFI_STATUS\r
126 VmWriteMem32 (\r
127   IN VM_CONTEXT *VmPtr,\r
128   UINTN         Addr,\r
129   IN UINT32     Data\r
130   );\r
131 \r
132 STATIC\r
133 UINT16\r
134 VmReadCode16 (\r
135   IN VM_CONTEXT *VmPtr,\r
136   IN UINT32     Offset\r
137   );\r
138 \r
139 STATIC\r
140 UINT32\r
141 VmReadCode32 (\r
142   IN VM_CONTEXT *VmPtr,\r
143   IN UINT32     Offset\r
144   );\r
145 \r
146 STATIC\r
147 UINT64\r
148 VmReadCode64 (\r
149   IN VM_CONTEXT *VmPtr,\r
150   IN UINT32     Offset\r
151   );\r
152 \r
153 STATIC\r
154 INT8\r
155 VmReadImmed8 (\r
156   IN VM_CONTEXT *VmPtr,\r
157   IN UINT32     Offset\r
158   );\r
159 \r
160 STATIC\r
161 INT16\r
162 VmReadImmed16 (\r
163   IN VM_CONTEXT *VmPtr,\r
164   IN UINT32     Offset\r
165   );\r
166 \r
167 STATIC\r
168 INT32\r
169 VmReadImmed32 (\r
170   IN VM_CONTEXT *VmPtr,\r
171   IN UINT32     Offset\r
172   );\r
173 \r
174 STATIC\r
175 INT64\r
176 VmReadImmed64 (\r
177   IN VM_CONTEXT *VmPtr,\r
178   IN UINT32     Offset\r
179   );\r
180 \r
181 STATIC\r
182 UINTN\r
183 ConvertStackAddr (\r
184   IN VM_CONTEXT   *VmPtr,\r
185   IN UINTN        Addr\r
186   );\r
187 \r
188 STATIC\r
189 EFI_STATUS\r
190 ExecuteDataManip (\r
191   IN VM_CONTEXT   *VmPtr,\r
192   IN BOOLEAN      IsSignedOperation\r
193   );\r
194 \r
195 //\r
196 // Functions that execute VM opcodes\r
197 //\r
198 STATIC\r
199 EFI_STATUS\r
200 ExecuteBREAK (\r
201   IN VM_CONTEXT *VmPtr\r
202   );\r
203 \r
204 STATIC\r
205 EFI_STATUS\r
206 ExecuteJMP (\r
207   IN VM_CONTEXT *VmPtr\r
208   );\r
209 \r
210 STATIC\r
211 EFI_STATUS\r
212 ExecuteJMP8 (\r
213   IN VM_CONTEXT *VmPtr\r
214   );\r
215 \r
216 STATIC\r
217 EFI_STATUS\r
218 ExecuteCALL (\r
219   IN VM_CONTEXT *VmPtr\r
220   );\r
221 \r
222 STATIC\r
223 EFI_STATUS\r
224 ExecuteRET (\r
225   IN VM_CONTEXT *VmPtr\r
226   );\r
227 \r
228 STATIC\r
229 EFI_STATUS\r
230 ExecuteCMP (\r
231   IN VM_CONTEXT *VmPtr\r
232   );\r
233 \r
234 STATIC\r
235 EFI_STATUS\r
236 ExecuteCMPI (\r
237   IN VM_CONTEXT *VmPtr\r
238   );\r
239 \r
240 STATIC\r
241 EFI_STATUS\r
242 ExecuteMOVxx (\r
243   IN VM_CONTEXT *VmPtr\r
244   );\r
245 \r
246 STATIC\r
247 EFI_STATUS\r
248 ExecuteMOVI (\r
249   IN VM_CONTEXT *VmPtr\r
250   );\r
251 \r
252 STATIC\r
253 EFI_STATUS\r
254 ExecuteMOVIn (\r
255   IN VM_CONTEXT *VmPtr\r
256   );\r
257 \r
258 STATIC\r
259 EFI_STATUS\r
260 ExecuteMOVREL (\r
261   IN VM_CONTEXT *VmPtr\r
262   );\r
263 \r
264 STATIC\r
265 EFI_STATUS\r
266 ExecutePUSHn (\r
267   IN VM_CONTEXT *VmPtr\r
268   );\r
269 \r
270 STATIC\r
271 EFI_STATUS\r
272 ExecutePUSH (\r
273   IN VM_CONTEXT *VmPtr\r
274   );\r
275 \r
276 STATIC\r
277 EFI_STATUS\r
278 ExecutePOPn (\r
279   IN VM_CONTEXT *VmPtr\r
280   );\r
281 \r
282 STATIC\r
283 EFI_STATUS\r
284 ExecutePOP (\r
285   IN VM_CONTEXT *VmPtr\r
286   );\r
287 \r
288 STATIC\r
289 EFI_STATUS\r
290 ExecuteSignedDataManip (\r
291   IN VM_CONTEXT *VmPtr\r
292   );\r
293 \r
294 STATIC\r
295 EFI_STATUS\r
296 ExecuteUnsignedDataManip (\r
297   IN VM_CONTEXT *VmPtr\r
298   );\r
299 \r
300 STATIC\r
301 EFI_STATUS\r
302 ExecuteLOADSP (\r
303   IN VM_CONTEXT *VmPtr\r
304   );\r
305 \r
306 STATIC\r
307 EFI_STATUS\r
308 ExecuteSTORESP (\r
309   IN VM_CONTEXT *VmPtr\r
310   );\r
311 \r
312 STATIC\r
313 EFI_STATUS\r
314 ExecuteMOVsnd (\r
315   IN VM_CONTEXT *VmPtr\r
316   );\r
317 \r
318 STATIC\r
319 EFI_STATUS\r
320 ExecuteMOVsnw (\r
321   IN VM_CONTEXT *VmPtr\r
322   );\r
323 \r
324 //\r
325 // Data manipulation subfunctions\r
326 //\r
327 STATIC\r
328 UINT64\r
329 ExecuteNOT (\r
330   IN VM_CONTEXT *VmPtr,\r
331   IN UINT64     Op1,\r
332   IN UINT64     Op2\r
333   );\r
334 \r
335 STATIC\r
336 UINT64\r
337 ExecuteNEG (\r
338   IN VM_CONTEXT *VmPtr,\r
339   IN UINT64     Op1,\r
340   IN UINT64     Op2\r
341   );\r
342 \r
343 STATIC\r
344 UINT64\r
345 ExecuteADD (\r
346   IN VM_CONTEXT *VmPtr,\r
347   IN UINT64     Op1,\r
348   IN UINT64     Op2\r
349   );\r
350 \r
351 STATIC\r
352 UINT64\r
353 ExecuteSUB (\r
354   IN VM_CONTEXT *VmPtr,\r
355   IN UINT64     Op1,\r
356   IN UINT64     Op2\r
357   );\r
358 \r
359 STATIC\r
360 UINT64\r
361 ExecuteMUL (\r
362   IN VM_CONTEXT *VmPtr,\r
363   IN UINT64     Op1,\r
364   IN UINT64     Op2\r
365   );\r
366 \r
367 STATIC\r
368 UINT64\r
369 ExecuteMULU (\r
370   IN VM_CONTEXT *VmPtr,\r
371   IN UINT64     Op1,\r
372   IN UINT64     Op2\r
373   );\r
374 \r
375 STATIC\r
376 UINT64\r
377 ExecuteDIV (\r
378   IN VM_CONTEXT *VmPtr,\r
379   IN UINT64     Op1,\r
380   IN UINT64     Op2\r
381   );\r
382 \r
383 STATIC\r
384 UINT64\r
385 ExecuteDIVU (\r
386   IN VM_CONTEXT *VmPtr,\r
387   IN UINT64     Op1,\r
388   IN UINT64     Op2\r
389   );\r
390 \r
391 STATIC\r
392 UINT64\r
393 ExecuteMOD (\r
394   IN VM_CONTEXT *VmPtr,\r
395   IN UINT64     Op1,\r
396   IN UINT64     Op2\r
397   );\r
398 \r
399 STATIC\r
400 UINT64\r
401 ExecuteMODU (\r
402   IN VM_CONTEXT *VmPtr,\r
403   IN UINT64     Op1,\r
404   IN UINT64     Op2\r
405   );\r
406 \r
407 STATIC\r
408 UINT64\r
409 ExecuteAND (\r
410   IN VM_CONTEXT *VmPtr,\r
411   IN UINT64     Op1,\r
412   IN UINT64     Op2\r
413   );\r
414 \r
415 STATIC\r
416 UINT64\r
417 ExecuteOR (\r
418   IN VM_CONTEXT *VmPtr,\r
419   IN UINT64     Op1,\r
420   IN UINT64     Op2\r
421   );\r
422 \r
423 STATIC\r
424 UINT64\r
425 ExecuteXOR (\r
426   IN VM_CONTEXT *VmPtr,\r
427   IN UINT64     Op1,\r
428   IN UINT64     Op2\r
429   );\r
430 \r
431 STATIC\r
432 UINT64\r
433 ExecuteSHL (\r
434   IN VM_CONTEXT *VmPtr,\r
435   IN UINT64     Op1,\r
436   IN UINT64     Op2\r
437   );\r
438 \r
439 STATIC\r
440 UINT64\r
441 ExecuteSHR (\r
442   IN VM_CONTEXT *VmPtr,\r
443   IN UINT64     Op1,\r
444   IN UINT64     Op2\r
445   );\r
446 \r
447 STATIC\r
448 UINT64\r
449 ExecuteASHR (\r
450   IN VM_CONTEXT *VmPtr,\r
451   IN UINT64     Op1,\r
452   IN UINT64     Op2\r
453   );\r
454 \r
455 STATIC\r
456 UINT64\r
457 ExecuteEXTNDB (\r
458   IN VM_CONTEXT *VmPtr,\r
459   IN UINT64     Op1,\r
460   IN UINT64     Op2\r
461   );\r
462 \r
463 STATIC\r
464 UINT64\r
465 ExecuteEXTNDW (\r
466   IN VM_CONTEXT *VmPtr,\r
467   IN UINT64     Op1,\r
468   IN UINT64     Op2\r
469   );\r
470 \r
471 STATIC\r
472 UINT64\r
473 ExecuteEXTNDD (\r
474   IN VM_CONTEXT *VmPtr,\r
475   IN UINT64     Op1,\r
476   IN UINT64     Op2\r
477   );\r
478 \r
479 //\r
480 // Once we retrieve the operands for the data manipulation instructions,\r
481 // call these functions to perform the operation.\r
482 //\r
483 static CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable[] = {\r
484   ExecuteNOT,\r
485   ExecuteNEG,\r
486   ExecuteADD,\r
487   ExecuteSUB,\r
488   ExecuteMUL,\r
489   ExecuteMULU,\r
490   ExecuteDIV,\r
491   ExecuteDIVU,\r
492   ExecuteMOD,\r
493   ExecuteMODU,\r
494   ExecuteAND,\r
495   ExecuteOR,\r
496   ExecuteXOR,\r
497   ExecuteSHL,\r
498   ExecuteSHR,\r
499   ExecuteASHR,\r
500   ExecuteEXTNDB,\r
501   ExecuteEXTNDW,\r
502   ExecuteEXTNDD,\r
503 };\r
504 \r
505 static CONST VM_TABLE_ENTRY           mVmOpcodeTable[] = {\r
506   { ExecuteBREAK },             // opcode 0x00\r
507   { ExecuteJMP },               // opcode 0x01\r
508   { ExecuteJMP8 },              // opcode 0x02\r
509   { ExecuteCALL },              // opcode 0x03\r
510   { ExecuteRET },               // opcode 0x04\r
511   { ExecuteCMP },               // opcode 0x05 CMPeq\r
512   { ExecuteCMP },               // opcode 0x06 CMPlte\r
513   { ExecuteCMP },               // opcode 0x07 CMPgte\r
514   { ExecuteCMP },               // opcode 0x08 CMPulte\r
515   { ExecuteCMP },               // opcode 0x09 CMPugte\r
516   { ExecuteUnsignedDataManip }, // opcode 0x0A NOT\r
517   { ExecuteSignedDataManip },   // opcode 0x0B NEG\r
518   { ExecuteSignedDataManip },   // opcode 0x0C ADD\r
519   { ExecuteSignedDataManip },   // opcode 0x0D SUB\r
520   { ExecuteSignedDataManip },   // opcode 0x0E MUL\r
521   { ExecuteUnsignedDataManip }, // opcode 0x0F MULU\r
522   { ExecuteSignedDataManip },   // opcode 0x10 DIV\r
523   { ExecuteUnsignedDataManip }, // opcode 0x11 DIVU\r
524   { ExecuteSignedDataManip },   // opcode 0x12 MOD\r
525   { ExecuteUnsignedDataManip }, // opcode 0x13 MODU\r
526   { ExecuteUnsignedDataManip }, // opcode 0x14 AND\r
527   { ExecuteUnsignedDataManip }, // opcode 0x15 OR\r
528   { ExecuteUnsignedDataManip }, // opcode 0x16 XOR\r
529   { ExecuteUnsignedDataManip }, // opcode 0x17 SHL\r
530   { ExecuteUnsignedDataManip }, // opcode 0x18 SHR\r
531   { ExecuteSignedDataManip },   // opcode 0x19 ASHR\r
532   { ExecuteUnsignedDataManip }, // opcode 0x1A EXTNDB\r
533   { ExecuteUnsignedDataManip }, // opcode 0x1B EXTNDW\r
534   { ExecuteUnsignedDataManip }, // opcode 0x1C EXTNDD\r
535   { ExecuteMOVxx },             // opcode 0x1D MOVBW\r
536   { ExecuteMOVxx },             // opcode 0x1E MOVWW\r
537   { ExecuteMOVxx },             // opcode 0x1F MOVDW\r
538   { ExecuteMOVxx },             // opcode 0x20 MOVQW\r
539   { ExecuteMOVxx },             // opcode 0x21 MOVBD\r
540   { ExecuteMOVxx },             // opcode 0x22 MOVWD\r
541   { ExecuteMOVxx },             // opcode 0x23 MOVDD\r
542   { ExecuteMOVxx },             // opcode 0x24 MOVQD\r
543   { ExecuteMOVsnw },            // opcode 0x25 MOVsnw\r
544   { ExecuteMOVsnd },            // opcode 0x26 MOVsnd\r
545   { NULL },                     // opcode 0x27\r
546   { ExecuteMOVxx },             // opcode 0x28 MOVqq\r
547   { ExecuteLOADSP },            // opcode 0x29 LOADSP SP1, R2\r
548   { ExecuteSTORESP },           // opcode 0x2A STORESP R1, SP2\r
549   { ExecutePUSH },              // opcode 0x2B PUSH {@}R1 [imm16]\r
550   { ExecutePOP },               // opcode 0x2C POP {@}R1 [imm16]\r
551   { ExecuteCMPI },              // opcode 0x2D CMPIEQ\r
552   { ExecuteCMPI },              // opcode 0x2E CMPILTE\r
553   { ExecuteCMPI },              // opcode 0x2F CMPIGTE\r
554   { ExecuteCMPI },              // opcode 0x30 CMPIULTE\r
555   { ExecuteCMPI },              // opcode 0x31 CMPIUGTE\r
556   { ExecuteMOVxx },             // opcode 0x32 MOVN\r
557   { ExecuteMOVxx },             // opcode 0x33 MOVND\r
558   { NULL },                     // opcode 0x34\r
559   { ExecutePUSHn },             // opcode 0x35\r
560   { ExecutePOPn },              // opcode 0x36\r
561   { ExecuteMOVI },              // opcode 0x37 - mov immediate data\r
562   { ExecuteMOVIn },             // opcode 0x38 - mov immediate natural\r
563   { ExecuteMOVREL }             // opcode 0x39 - move data relative to PC\r
564 };\r
565 \r
566 //\r
567 // Length of JMP instructions, depending on upper two bits of opcode.\r
568 //\r
569 static CONST UINT8                    mJMPLen[] = { 2, 2, 6, 10 };\r
570 \r
571 //\r
572 // Simple Debugger Protocol GUID\r
573 //\r
574 EFI_GUID mEbcSimpleDebuggerProtocolGuid = EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID;\r
575 \r
576 EFI_STATUS\r
577 EbcExecuteInstructions (\r
578   IN EFI_EBC_VM_TEST_PROTOCOL *This,\r
579   IN VM_CONTEXT               *VmPtr,\r
580   IN OUT UINTN                *InstructionCount\r
581   )\r
582 /*++\r
583 \r
584 Routine Description:\r
585   \r
586   Given a pointer to a new VM context, execute one or more instructions. This\r
587   function is only used for test purposes via the EBC VM test protocol.\r
588 \r
589 Arguments:\r
590 \r
591   This              - pointer to protocol interface\r
592   VmPtr             - pointer to a VM context\r
593   InstructionCount  - how many instructions to execute. 0 if don't count.\r
594 \r
595 Returns:\r
596 \r
597   EFI_UNSUPPORTED\r
598   EFI_SUCCESS\r
599 \r
600 --*/\r
601 {\r
602   UINTN       ExecFunc;\r
603   EFI_STATUS  Status;\r
604   UINTN       InstructionsLeft;\r
605   UINTN       SavedInstructionCount;\r
606 \r
607   Status = EFI_SUCCESS;\r
608 \r
609   if (*InstructionCount == 0) {\r
610     InstructionsLeft = 1;\r
611   } else {\r
612     InstructionsLeft = *InstructionCount;\r
613   }\r
614 \r
615   SavedInstructionCount = *InstructionCount;\r
616   *InstructionCount     = 0;\r
617 \r
618   //\r
619   // Index into the opcode table using the opcode byte for this instruction.\r
620   // This gives you the execute function, which we first test for null, then\r
621   // call it if it's not null.\r
622   //\r
623   while (InstructionsLeft != 0) {\r
624     ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & 0x3F)].ExecuteFunction;\r
625     if (ExecFunc == (UINTN) NULL) {\r
626       EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);\r
627       return EFI_UNSUPPORTED;\r
628     } else {\r
629       mVmOpcodeTable[(*VmPtr->Ip & 0x3F)].ExecuteFunction (VmPtr);\r
630       *InstructionCount = *InstructionCount + 1;\r
631     }\r
632 \r
633     //\r
634     // Decrement counter if applicable\r
635     //\r
636     if (SavedInstructionCount != 0) {\r
637       InstructionsLeft--;\r
638     }\r
639   }\r
640 \r
641   return Status;\r
642 }\r
643 \r
644 EFI_STATUS\r
645 EbcExecute (\r
646   IN VM_CONTEXT *VmPtr\r
647   )\r
648 /*++\r
649 \r
650 Routine Description:\r
651   \r
652   Execute an EBC image from an entry point or from a published protocol.\r
653 \r
654 Arguments:\r
655 \r
656   VmPtr - pointer to prepared VM context.\r
657 \r
658 Returns:\r
659 \r
660   Standard EBC status.\r
661 \r
662 --*/\r
663 {\r
664   UINTN                             ExecFunc;\r
665   UINT8                             StackCorrupted;\r
666   EFI_STATUS                        Status;\r
667   EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL  *EbcSimpleDebugger;\r
668 \r
669   mVmPtr            = VmPtr;\r
670   EbcSimpleDebugger = NULL;\r
671   Status            = EFI_SUCCESS;\r
672   StackCorrupted    = 0;\r
673 \r
674   //\r
675   // Make sure the magic value has been put on the stack before we got here.\r
676   //\r
677   if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {\r
678     StackCorrupted = 1;\r
679   }\r
680 \r
681   VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->R[0] + 8);\r
682 \r
683   //\r
684   // Try to get the debug support for EBC\r
685   //\r
686   DEBUG_CODE_BEGIN ();\r
687     Status = gBS->LocateProtocol (\r
688                     &mEbcSimpleDebuggerProtocolGuid,\r
689                     NULL,\r
690                     (VOID **) &EbcSimpleDebugger\r
691                     );\r
692     if (EFI_ERROR (Status)) {\r
693       EbcSimpleDebugger = NULL;\r
694     }\r
695   DEBUG_CODE_END ();\r
696 \r
697   //\r
698   // Save the start IP for debug. For example, if we take an exception we\r
699   // can print out the location of the exception relative to the entry point,\r
700   // which could then be used in a disassembly listing to find the problem.\r
701   //\r
702   VmPtr->EntryPoint = (VOID *) VmPtr->Ip;\r
703 \r
704   //\r
705   // We'll wait for this flag to know when we're done. The RET\r
706   // instruction sets it if it runs out of stack.\r
707   //\r
708   VmPtr->StopFlags = 0;\r
709   while (!(VmPtr->StopFlags & STOPFLAG_APP_DONE)) {\r
710     //\r
711     // If we've found a simple debugger protocol, call it\r
712     //\r
713     DEBUG_CODE_BEGIN ();\r
714       if (EbcSimpleDebugger != NULL) {\r
715         EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);\r
716       }\r
717     DEBUG_CODE_END ();\r
718 \r
719     //\r
720     // Verify the opcode is in range. Otherwise generate an exception.\r
721     //\r
722     if ((*VmPtr->Ip & OPCODE_M_OPCODE) >= (sizeof (mVmOpcodeTable) / sizeof (mVmOpcodeTable[0]))) {\r
723       EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);\r
724       Status = EFI_UNSUPPORTED;\r
725       goto Done;\r
726     }\r
727     //\r
728     // Use the opcode bits to index into the opcode dispatch table. If the\r
729     // function pointer is null then generate an exception.\r
730     //\r
731     ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;\r
732     if (ExecFunc == (UINTN) NULL) {\r
733       EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);\r
734       Status = EFI_UNSUPPORTED;\r
735       goto Done;\r
736     }\r
737     //\r
738     // The EBC VM is a strongly ordered processor, so perform a fence operation before\r
739     // and after each instruction is executed.\r
740     //\r
741     MemoryFence ();\r
742 \r
743     mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);\r
744 \r
745     MemoryFence ();\r
746 \r
747     //\r
748     // If the step flag is set, signal an exception and continue. We don't\r
749     // clear it here. Assuming the debugger is responsible for clearing it.\r
750     //\r
751     if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {\r
752       EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);\r
753     }\r
754     //\r
755     // Make sure stack has not been corrupted. Only report it once though.\r
756     //\r
757     if (!StackCorrupted && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {\r
758       EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);\r
759       StackCorrupted = 1;\r
760     }\r
761     if (!StackCorrupted && ((UINT64)VmPtr->R[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {\r
762       EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);\r
763       StackCorrupted = 1;\r
764     }\r
765   }\r
766 \r
767 Done:\r
768   mVmPtr          = NULL;\r
769 \r
770   return Status;\r
771 }\r
772 \r
773 STATIC\r
774 EFI_STATUS\r
775 ExecuteMOVxx (\r
776   IN VM_CONTEXT *VmPtr\r
777   )\r
778 /*++\r
779 \r
780 Routine Description:\r
781   \r
782   Execute the MOVxx instructions.\r
783 \r
784 Arguments:\r
785 \r
786   VmPtr - pointer to a VM context.\r
787 \r
788 Returns:\r
789 \r
790   EFI_UNSUPPORTED\r
791   EFI_SUCCESS\r
792 \r
793 Instruction format:\r
794   \r
795   MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}\r
796   MOVqq {@}R1 {Index64}, {@}R2 {Index64}\r
797 \r
798   Copies contents of [R2] -> [R1], zero extending where required.\r
799 \r
800   First character indicates the size of the move.\r
801   Second character indicates the size of the index(s).\r
802 \r
803   Invalid to have R1 direct with index.\r
804   \r
805 --*/\r
806 {\r
807   UINT8   Opcode;\r
808   UINT8   OpcMasked;\r
809   UINT8   Operands;\r
810   UINT8   Size;\r
811   UINT8   MoveSize;\r
812   INT16   Index16;\r
813   INT32   Index32;\r
814   INT64   Index64Op1;\r
815   INT64   Index64Op2;\r
816   UINT64  Data64;\r
817   UINT64  DataMask;\r
818   UINTN   Source;\r
819 \r
820   Opcode    = GETOPCODE (VmPtr);\r
821   OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);\r
822 \r
823   //\r
824   // Get the operands byte so we can get R1 and R2\r
825   //\r
826   Operands = GETOPERANDS (VmPtr);\r
827 \r
828   //\r
829   // Assume no indexes\r
830   //\r
831   Index64Op1  = 0;\r
832   Index64Op2  = 0;\r
833   Data64      = 0;\r
834 \r
835   //\r
836   // Determine if we have an index/immediate data. Base instruction size\r
837   // is 2 (opcode + operands). Add to this size each index specified.\r
838   //\r
839   Size = 2;\r
840   if (Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) {\r
841     //\r
842     // Determine size of the index from the opcode. Then get it.\r
843     //\r
844     if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {\r
845       //\r
846       // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.\r
847       // Get one or both index values.\r
848       //\r
849       if (Opcode & OPCODE_M_IMMED_OP1) {\r
850         Index16     = VmReadIndex16 (VmPtr, 2);\r
851         Index64Op1  = (INT64) Index16;\r
852         Size += sizeof (UINT16);\r
853       }\r
854 \r
855       if (Opcode & OPCODE_M_IMMED_OP2) {\r
856         Index16     = VmReadIndex16 (VmPtr, Size);\r
857         Index64Op2  = (INT64) Index16;\r
858         Size += sizeof (UINT16);\r
859       }\r
860     } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {\r
861       //\r
862       // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index\r
863       //\r
864       if (Opcode & OPCODE_M_IMMED_OP1) {\r
865         Index32     = VmReadIndex32 (VmPtr, 2);\r
866         Index64Op1  = (INT64) Index32;\r
867         Size += sizeof (UINT32);\r
868       }\r
869 \r
870       if (Opcode & OPCODE_M_IMMED_OP2) {\r
871         Index32     = VmReadIndex32 (VmPtr, Size);\r
872         Index64Op2  = (INT64) Index32;\r
873         Size += sizeof (UINT32);\r
874       }\r
875     } else if (OpcMasked == OPCODE_MOVQQ) {\r
876       //\r
877       // MOVqq -- only form with a 64-bit index\r
878       //\r
879       if (Opcode & OPCODE_M_IMMED_OP1) {\r
880         Index64Op1 = VmReadIndex64 (VmPtr, 2);\r
881         Size += sizeof (UINT64);\r
882       }\r
883 \r
884       if (Opcode & OPCODE_M_IMMED_OP2) {\r
885         Index64Op2 = VmReadIndex64 (VmPtr, Size);\r
886         Size += sizeof (UINT64);\r
887       }\r
888     } else {\r
889       //\r
890       // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index\r
891       //\r
892       EbcDebugSignalException (\r
893         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
894         EXCEPTION_FLAG_FATAL,\r
895         VmPtr\r
896         );\r
897       return EFI_UNSUPPORTED;\r
898     }\r
899   }\r
900   //\r
901   // Determine the size of the move, and create a mask for it so we can\r
902   // clear unused bits.\r
903   //\r
904   if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {\r
905     MoveSize  = DATA_SIZE_8;\r
906     DataMask  = 0xFF;\r
907   } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {\r
908     MoveSize  = DATA_SIZE_16;\r
909     DataMask  = 0xFFFF;\r
910   } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {\r
911     MoveSize  = DATA_SIZE_32;\r
912     DataMask  = 0xFFFFFFFF;\r
913   } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {\r
914     MoveSize  = DATA_SIZE_64;\r
915     DataMask  = (UINT64)~0;\r
916   } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {\r
917     MoveSize  = DATA_SIZE_N;\r
918     DataMask  = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));\r
919   } else {\r
920     //\r
921     // We were dispatched to this function and we don't recognize the opcode\r
922     //\r
923     EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);\r
924     return EFI_UNSUPPORTED;\r
925   }\r
926   //\r
927   // Now get the source address\r
928   //\r
929   if (OPERAND2_INDIRECT (Operands)) {\r
930     //\r
931     // Indirect form @R2. Compute address of operand2\r
932     //\r
933     Source = (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index64Op2);\r
934     //\r
935     // Now get the data from the source. Always 0-extend and let the compiler\r
936     // sign-extend where required.\r
937     //\r
938     switch (MoveSize) {\r
939     case DATA_SIZE_8:\r
940       Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);\r
941       break;\r
942 \r
943     case DATA_SIZE_16:\r
944       Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);\r
945       break;\r
946 \r
947     case DATA_SIZE_32:\r
948       Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);\r
949       break;\r
950 \r
951     case DATA_SIZE_64:\r
952       Data64 = (UINT64) VmReadMem64 (VmPtr, Source);\r
953       break;\r
954 \r
955     case DATA_SIZE_N:\r
956       Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);\r
957       break;\r
958 \r
959     default:\r
960       //\r
961       // not reached\r
962       //\r
963       break;\r
964     }\r
965   } else {\r
966     //\r
967     // Not indirect source: MOVxx {@}Rx, Ry [Index]\r
968     //\r
969     Data64 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index64Op2;\r
970     //\r
971     // Did Operand2 have an index? If so, treat as two signed values since\r
972     // indexes are signed values.\r
973     //\r
974     if (Opcode & OPCODE_M_IMMED_OP2) {\r
975       //\r
976       // NOTE: need to find a way to fix this, most likely by changing the VM\r
977       // implementation to remove the stack gap. To do that, we'd need to\r
978       // allocate stack space for the VM and actually set the system\r
979       // stack pointer to the allocated buffer when the VM starts.\r
980       //\r
981       // Special case -- if someone took the address of a function parameter\r
982       // then we need to make sure it's not in the stack gap. We can identify\r
983       // this situation if (Operand2 register == 0) && (Operand2 is direct)\r
984       // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)\r
985       // Situations that to be aware of:\r
986       //   * stack adjustments at beginning and end of functions R0 = R0 += stacksize\r
987       //\r
988       if ((OPERAND2_REGNUM (Operands) == 0) &&\r
989           (!OPERAND2_INDIRECT (Operands)) &&\r
990           (Index64Op2 > 0) &&\r
991           (OPERAND1_REGNUM (Operands) == 0) &&\r
992           (OPERAND1_INDIRECT (Operands))\r
993           ) {\r
994         Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);\r
995       }\r
996     }\r
997   }\r
998   //\r
999   // Now write it back\r
1000   //\r
1001   if (OPERAND1_INDIRECT (Operands)) {\r
1002     //\r
1003     // Reuse the Source variable to now be dest.\r
1004     //\r
1005     Source = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index64Op1);\r
1006     //\r
1007     // Do the write based on the size\r
1008     //\r
1009     switch (MoveSize) {\r
1010     case DATA_SIZE_8:\r
1011       VmWriteMem8 (VmPtr, Source, (UINT8) Data64);\r
1012       break;\r
1013 \r
1014     case DATA_SIZE_16:\r
1015       VmWriteMem16 (VmPtr, Source, (UINT16) Data64);\r
1016       break;\r
1017 \r
1018     case DATA_SIZE_32:\r
1019       VmWriteMem32 (VmPtr, Source, (UINT32) Data64);\r
1020       break;\r
1021 \r
1022     case DATA_SIZE_64:\r
1023       VmWriteMem64 (VmPtr, Source, Data64);\r
1024       break;\r
1025 \r
1026     case DATA_SIZE_N:\r
1027       VmWriteMemN (VmPtr, Source, (UINTN) Data64);\r
1028       break;\r
1029 \r
1030     default:\r
1031       //\r
1032       // not reached\r
1033       //\r
1034       break;\r
1035     }\r
1036   } else {\r
1037     //\r
1038     // Operand1 direct.\r
1039     // Make sure we didn't have an index on operand1.\r
1040     //\r
1041     if (Opcode & OPCODE_M_IMMED_OP1) {\r
1042       EbcDebugSignalException (\r
1043         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1044         EXCEPTION_FLAG_FATAL,\r
1045         VmPtr\r
1046         );\r
1047       return EFI_UNSUPPORTED;\r
1048     }\r
1049     //\r
1050     // Direct storage in register. Clear unused bits and store back to\r
1051     // register.\r
1052     //\r
1053     VmPtr->R[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;\r
1054   }\r
1055   //\r
1056   // Advance the instruction pointer\r
1057   //\r
1058   VmPtr->Ip += Size;\r
1059   return EFI_SUCCESS;\r
1060 }\r
1061 \r
1062 STATIC\r
1063 EFI_STATUS\r
1064 ExecuteBREAK (\r
1065   IN VM_CONTEXT *VmPtr\r
1066   )\r
1067 /*++\r
1068 \r
1069 Routine Description:\r
1070   \r
1071   Execute the EBC BREAK instruction\r
1072 \r
1073 Arguments:\r
1074 \r
1075   VmPtr - pointer to current VM context\r
1076 \r
1077 Returns:\r
1078 \r
1079   EFI_UNSUPPORTED\r
1080   EFI_SUCCESS\r
1081 \r
1082 --*/\r
1083 {\r
1084   UINT8       Operands;\r
1085   VOID        *EbcEntryPoint;\r
1086   VOID        *Thunk;\r
1087   UINT64      U64EbcEntryPoint;\r
1088   INT32       Offset;\r
1089 \r
1090   Operands = GETOPERANDS (VmPtr);\r
1091   switch (Operands) {\r
1092   //\r
1093   // Runaway program break. Generate an exception and terminate\r
1094   //\r
1095   case 0:\r
1096     EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);\r
1097     break;\r
1098 \r
1099   //\r
1100   // Get VM version -- return VM revision number in R7\r
1101   //\r
1102   case 1:\r
1103     //\r
1104     // Bits:\r
1105     //  63-17 = 0\r
1106     //  16-8  = Major version\r
1107     //  7-0   = Minor version\r
1108     //\r
1109     VmPtr->R[7] = GetVmVersion ();\r
1110     break;\r
1111 \r
1112   //\r
1113   // Debugger breakpoint\r
1114   //\r
1115   case 3:\r
1116     VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;\r
1117     //\r
1118     // See if someone has registered a handler\r
1119     //\r
1120     EbcDebugSignalException (\r
1121       EXCEPT_EBC_BREAKPOINT,\r
1122       EXCEPTION_FLAG_NONE,\r
1123       VmPtr\r
1124       );\r
1125     break;\r
1126 \r
1127   //\r
1128   // System call, which there are none, so NOP it.\r
1129   //\r
1130   case 4:\r
1131     break;\r
1132 \r
1133   //\r
1134   // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)\r
1135   // "offset from self" pointer to the EBC entry point.\r
1136   // After we're done, *(UINT64 *)R7 will be the address of the new thunk.\r
1137   //\r
1138   case 5:\r
1139     Offset            = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->R[7]);\r
1140     U64EbcEntryPoint  = (UINT64) (VmPtr->R[7] + Offset + 4);\r
1141     EbcEntryPoint     = (VOID *) (UINTN) U64EbcEntryPoint;\r
1142 \r
1143     //\r
1144     // Now create a new thunk\r
1145     //\r
1146     EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);\r
1147 \r
1148     //\r
1149     // Finally replace the EBC entry point memory with the thunk address\r
1150     //\r
1151     VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[7], (UINT64) (UINTN) Thunk);\r
1152     break;\r
1153 \r
1154   //\r
1155   // Compiler setting version per value in R7\r
1156   //\r
1157   case 6:\r
1158     VmPtr->CompilerVersion = (UINT32) VmPtr->R[7];\r
1159     //\r
1160     // Check compiler version against VM version?\r
1161     //\r
1162     break;\r
1163 \r
1164   //\r
1165   // Unhandled break code. Signal exception.\r
1166   //\r
1167   default:\r
1168     EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);\r
1169     break;\r
1170   }\r
1171   //\r
1172   // Advance IP\r
1173   //\r
1174   VmPtr->Ip += 2;\r
1175   return EFI_SUCCESS;\r
1176 }\r
1177 \r
1178 STATIC\r
1179 EFI_STATUS\r
1180 ExecuteJMP (\r
1181   IN VM_CONTEXT *VmPtr\r
1182   )\r
1183 /*++\r
1184 \r
1185 Routine Description:\r
1186   Execute the JMP instruction\r
1187 \r
1188 Arguments:\r
1189   VmPtr      - pointer to VM context\r
1190 \r
1191 Returns:\r
1192   Standard EFI_STATUS\r
1193 \r
1194 Instruction syntax:\r
1195   JMP64{cs|cc} Immed64\r
1196   JMP32{cs|cc} {@}R1 {Immed32|Index32}\r
1197 \r
1198 Encoding:\r
1199   b0.7 -  immediate data present\r
1200   b0.6 -  1 = 64 bit immediate data\r
1201           0 = 32 bit immediate data\r
1202   b1.7 -  1 = conditional\r
1203   b1.6    1 = CS (condition set)\r
1204           0 = CC (condition clear)\r
1205   b1.4    1 = relative address\r
1206           0 = absolute address\r
1207   b1.3    1 = operand1 indirect\r
1208   b1.2-0  operand 1\r
1209 \r
1210 --*/\r
1211 {\r
1212   UINT8   Opcode;\r
1213   UINT8   CompareSet;\r
1214   UINT8   ConditionFlag;\r
1215   UINT8   Size;\r
1216   UINT8   Operand;\r
1217   UINT64  Data64;\r
1218   INT32   Index32;\r
1219   UINTN   Addr;\r
1220 \r
1221   Operand = GETOPERANDS (VmPtr);\r
1222   Opcode  = GETOPCODE (VmPtr);\r
1223 \r
1224   //\r
1225   // Get instruction length from the opcode. The upper two bits are used here\r
1226   // to index into the length array.\r
1227   //\r
1228   Size = mJMPLen[(Opcode >> 6) & 0x03];\r
1229 \r
1230   //\r
1231   // Decode instruction conditions\r
1232   // If we haven't met the condition, then simply advance the IP and return.\r
1233   //\r
1234   CompareSet    = (UINT8) ((Operand & JMP_M_CS) ? 1 : 0);\r
1235   ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);\r
1236   if (Operand & CONDITION_M_CONDITIONAL) {\r
1237     if (CompareSet != ConditionFlag) {\r
1238       VmPtr->Ip += Size;\r
1239       return EFI_SUCCESS;\r
1240     }\r
1241   }\r
1242   //\r
1243   // Check for 64-bit form and do it right away since it's the most\r
1244   // straight-forward form.\r
1245   //\r
1246   if (Opcode & OPCODE_M_IMMDATA64) {\r
1247     //\r
1248     // Double check for immediate-data, which is required. If not there,\r
1249     // then signal an exception\r
1250     //\r
1251     if (!(Opcode & OPCODE_M_IMMDATA)) {\r
1252       EbcDebugSignalException (\r
1253         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1254         EXCEPTION_FLAG_ERROR,\r
1255         VmPtr\r
1256         );\r
1257       return EFI_UNSUPPORTED;\r
1258     }\r
1259     //\r
1260     // 64-bit immediate data is full address. Read the immediate data,\r
1261     // check for alignment, and jump absolute.\r
1262     //\r
1263     Data64 = VmReadImmed64 (VmPtr, 2);\r
1264     if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {\r
1265       EbcDebugSignalException (\r
1266         EXCEPT_EBC_ALIGNMENT_CHECK,\r
1267         EXCEPTION_FLAG_FATAL,\r
1268         VmPtr\r
1269         );\r
1270 \r
1271       return EFI_UNSUPPORTED;\r
1272     }\r
1273 \r
1274     //\r
1275     // Take jump -- relative or absolute\r
1276     //\r
1277     if (Operand & JMP_M_RELATIVE) {\r
1278       VmPtr->Ip += (UINTN) Data64 + Size;\r
1279     } else {\r
1280       VmPtr->Ip = (VMIP) (UINTN) Data64;\r
1281     }\r
1282 \r
1283     return EFI_SUCCESS;\r
1284   }\r
1285   //\r
1286   // 32-bit forms:\r
1287   // Get the index if there is one. May be either an index, or an immediate\r
1288   // offset depending on indirect operand.\r
1289   //   JMP32 @R1 Index32 -- immediate data is an index\r
1290   //   JMP32 R1 Immed32  -- immedate data is an offset\r
1291   //\r
1292   if (Opcode & OPCODE_M_IMMDATA) {\r
1293     if (OPERAND1_INDIRECT (Operand)) {\r
1294       Index32 = VmReadIndex32 (VmPtr, 2);\r
1295     } else {\r
1296       Index32 = VmReadImmed32 (VmPtr, 2);\r
1297     }\r
1298   } else {\r
1299     Index32 = 0;\r
1300   }\r
1301   //\r
1302   // Get the register data. If R == 0, then special case where it's ignored.\r
1303   //\r
1304   if (OPERAND1_REGNUM (Operand) == 0) {\r
1305     Data64 = 0;\r
1306   } else {\r
1307     Data64 = OPERAND1_REGDATA (VmPtr, Operand);\r
1308   }\r
1309   //\r
1310   // Decode the forms\r
1311   //\r
1312   if (OPERAND1_INDIRECT (Operand)) {\r
1313     //\r
1314     // Form: JMP32 @Rx {Index32}\r
1315     //\r
1316     Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);\r
1317     if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {\r
1318       EbcDebugSignalException (\r
1319         EXCEPT_EBC_ALIGNMENT_CHECK,\r
1320         EXCEPTION_FLAG_FATAL,\r
1321         VmPtr\r
1322         );\r
1323 \r
1324       return EFI_UNSUPPORTED;\r
1325     }\r
1326 \r
1327     if (Operand & JMP_M_RELATIVE) {\r
1328       VmPtr->Ip += (UINTN) Addr + Size;\r
1329     } else {\r
1330       VmPtr->Ip = (VMIP) Addr;\r
1331     }\r
1332   } else {\r
1333     //\r
1334     // Form: JMP32 Rx {Immed32}\r
1335     //\r
1336     Addr = (UINTN) (Data64 + Index32);\r
1337     if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {\r
1338       EbcDebugSignalException (\r
1339         EXCEPT_EBC_ALIGNMENT_CHECK,\r
1340         EXCEPTION_FLAG_FATAL,\r
1341         VmPtr\r
1342         );\r
1343 \r
1344       return EFI_UNSUPPORTED;\r
1345     }\r
1346 \r
1347     if (Operand & JMP_M_RELATIVE) {\r
1348       VmPtr->Ip += (UINTN) Addr + Size;\r
1349     } else {\r
1350       VmPtr->Ip = (VMIP) Addr;\r
1351     }\r
1352   }\r
1353 \r
1354   return EFI_SUCCESS;\r
1355 }\r
1356 \r
1357 STATIC\r
1358 EFI_STATUS\r
1359 ExecuteJMP8 (\r
1360   IN VM_CONTEXT *VmPtr\r
1361   )\r
1362 /*++\r
1363 \r
1364 Routine Description:\r
1365   Execute the EBC JMP8 instruction\r
1366 \r
1367 Arguments:\r
1368   VmPtr   - pointer to a VM context  \r
1369 \r
1370 Returns:\r
1371   Standard EFI_STATUS\r
1372 \r
1373 Instruction syntax:\r
1374   JMP8{cs|cc}  Offset/2\r
1375 \r
1376 --*/\r
1377 {\r
1378   UINT8 Opcode;\r
1379   UINT8 ConditionFlag;\r
1380   UINT8 CompareSet;\r
1381   INT8  Offset;\r
1382 \r
1383   //\r
1384   // Decode instruction.\r
1385   //\r
1386   Opcode        = GETOPCODE (VmPtr);\r
1387   CompareSet    = (UINT8) ((Opcode & JMP_M_CS) ? 1 : 0);\r
1388   ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);\r
1389 \r
1390   //\r
1391   // If we haven't met the condition, then simply advance the IP and return\r
1392   //\r
1393   if (Opcode & CONDITION_M_CONDITIONAL) {\r
1394     if (CompareSet != ConditionFlag) {\r
1395       VmPtr->Ip += 2;\r
1396       return EFI_SUCCESS;\r
1397     }\r
1398   }\r
1399   //\r
1400   // Get the offset from the instruction stream. It's relative to the\r
1401   // following instruction, and divided by 2.\r
1402   //\r
1403   Offset = VmReadImmed8 (VmPtr, 1);\r
1404   //\r
1405   // Want to check for offset == -2 and then raise an exception?\r
1406   //\r
1407   VmPtr->Ip += (Offset * 2) + 2;\r
1408   return EFI_SUCCESS;\r
1409 }\r
1410 \r
1411 STATIC\r
1412 EFI_STATUS\r
1413 ExecuteMOVI (\r
1414   IN VM_CONTEXT *VmPtr\r
1415   )\r
1416 /*++\r
1417 \r
1418 Routine Description:\r
1419   \r
1420   Execute the EBC MOVI \r
1421 \r
1422 Arguments:\r
1423 \r
1424   VmPtr   - pointer to a VM context  \r
1425 \r
1426 Returns:\r
1427 \r
1428   Standard EFI_STATUS\r
1429 \r
1430 Instruction syntax:\r
1431 \r
1432   MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
1433 \r
1434   First variable character specifies the move size\r
1435   Second variable character specifies size of the immediate data\r
1436 \r
1437   Sign-extend the immediate data to the size of the operation, and zero-extend\r
1438   if storing to a register.\r
1439 \r
1440   Operand1 direct with index/immed is invalid.\r
1441     \r
1442 --*/\r
1443 {\r
1444   UINT8   Opcode;\r
1445   UINT8   Operands;\r
1446   UINT8   Size;\r
1447   INT16   Index16;\r
1448   INT64   ImmData64;\r
1449   UINT64  Op1;\r
1450   UINT64  Mask64;\r
1451 \r
1452   //\r
1453   // Get the opcode and operands byte so we can get R1 and R2\r
1454   //\r
1455   Opcode    = GETOPCODE (VmPtr);\r
1456   Operands  = GETOPERANDS (VmPtr);\r
1457 \r
1458   //\r
1459   // Get the index (16-bit) if present\r
1460   //\r
1461   if (Operands & MOVI_M_IMMDATA) {\r
1462     Index16 = VmReadIndex16 (VmPtr, 2);\r
1463     Size    = 4;\r
1464   } else {\r
1465     Index16 = 0;\r
1466     Size    = 2;\r
1467   }\r
1468   //\r
1469   // Extract the immediate data. Sign-extend always.\r
1470   //\r
1471   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
1472     ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);\r
1473     Size += 2;\r
1474   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
1475     ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);\r
1476     Size += 4;\r
1477   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
1478     ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);\r
1479     Size += 8;\r
1480   } else {\r
1481     //\r
1482     // Invalid encoding\r
1483     //\r
1484     EbcDebugSignalException (\r
1485       EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1486       EXCEPTION_FLAG_FATAL,\r
1487       VmPtr\r
1488       );\r
1489     return EFI_UNSUPPORTED;\r
1490   }\r
1491   //\r
1492   // Now write back the result\r
1493   //\r
1494   if (!OPERAND1_INDIRECT (Operands)) {\r
1495     //\r
1496     // Operand1 direct. Make sure it didn't have an index.\r
1497     //\r
1498     if (Operands & MOVI_M_IMMDATA) {\r
1499       EbcDebugSignalException (\r
1500         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1501         EXCEPTION_FLAG_FATAL,\r
1502         VmPtr\r
1503         );\r
1504       return EFI_UNSUPPORTED;\r
1505     }\r
1506     //\r
1507     // Writing directly to a register. Clear unused bits.\r
1508     //\r
1509     if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {\r
1510       Mask64 = 0x000000FF;\r
1511     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {\r
1512       Mask64 = 0x0000FFFF;\r
1513     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {\r
1514       Mask64 = 0x00000000FFFFFFFF;\r
1515     } else {\r
1516       Mask64 = (UINT64)~0;\r
1517     }\r
1518 \r
1519     VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;\r
1520   } else {\r
1521     //\r
1522     // Get the address then write back based on size of the move\r
1523     //\r
1524     Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;\r
1525     if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {\r
1526       VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);\r
1527     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {\r
1528       VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);\r
1529     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {\r
1530       VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);\r
1531     } else {\r
1532       VmWriteMem64 (VmPtr, (UINTN) Op1, ImmData64);\r
1533     }\r
1534   }\r
1535   //\r
1536   // Advance the instruction pointer\r
1537   //\r
1538   VmPtr->Ip += Size;\r
1539   return EFI_SUCCESS;\r
1540 }\r
1541 \r
1542 STATIC\r
1543 EFI_STATUS\r
1544 ExecuteMOVIn (\r
1545   IN VM_CONTEXT *VmPtr\r
1546   )\r
1547 /*++\r
1548 \r
1549 Routine Description:\r
1550   \r
1551   Execute the EBC MOV immediate natural. This instruction moves an immediate\r
1552   index value into a register or memory location.\r
1553 \r
1554 Arguments:\r
1555 \r
1556   VmPtr   - pointer to a VM context  \r
1557 \r
1558 Returns:\r
1559 \r
1560   Standard EFI_STATUS\r
1561 \r
1562 Instruction syntax:\r
1563 \r
1564   MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64\r
1565 \r
1566 --*/\r
1567 {\r
1568   UINT8   Opcode;\r
1569   UINT8   Operands;\r
1570   UINT8   Size;\r
1571   INT16   Index16;\r
1572   INT16   ImmedIndex16;\r
1573   INT32   ImmedIndex32;\r
1574   INT64   ImmedIndex64;\r
1575   UINT64  Op1;\r
1576 \r
1577   //\r
1578   // Get the opcode and operands byte so we can get R1 and R2\r
1579   //\r
1580   Opcode    = GETOPCODE (VmPtr);\r
1581   Operands  = GETOPERANDS (VmPtr);\r
1582 \r
1583   //\r
1584   // Get the operand1 index (16-bit) if present\r
1585   //\r
1586   if (Operands & MOVI_M_IMMDATA) {\r
1587     Index16 = VmReadIndex16 (VmPtr, 2);\r
1588     Size    = 4;\r
1589   } else {\r
1590     Index16 = 0;\r
1591     Size    = 2;\r
1592   }\r
1593   //\r
1594   // Extract the immediate data and convert to a 64-bit index.\r
1595   //\r
1596   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
1597     ImmedIndex16  = VmReadIndex16 (VmPtr, Size);\r
1598     ImmedIndex64  = (INT64) ImmedIndex16;\r
1599     Size += 2;\r
1600   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
1601     ImmedIndex32  = VmReadIndex32 (VmPtr, Size);\r
1602     ImmedIndex64  = (INT64) ImmedIndex32;\r
1603     Size += 4;\r
1604   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
1605     ImmedIndex64 = VmReadIndex64 (VmPtr, Size);\r
1606     Size += 8;\r
1607   } else {\r
1608     //\r
1609     // Invalid encoding\r
1610     //\r
1611     EbcDebugSignalException (\r
1612       EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1613       EXCEPTION_FLAG_FATAL,\r
1614       VmPtr\r
1615       );\r
1616     return EFI_UNSUPPORTED;\r
1617   }\r
1618   //\r
1619   // Now write back the result\r
1620   //\r
1621   if (!OPERAND1_INDIRECT (Operands)) {\r
1622     //\r
1623     // Check for MOVIn R1 Index16, Immed (not indirect, with index), which\r
1624     // is illegal\r
1625     //\r
1626     if (Operands & MOVI_M_IMMDATA) {\r
1627       EbcDebugSignalException (\r
1628         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1629         EXCEPTION_FLAG_FATAL,\r
1630         VmPtr\r
1631         );\r
1632       return EFI_UNSUPPORTED;\r
1633     }\r
1634 \r
1635     VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmedIndex64;\r
1636   } else {\r
1637     //\r
1638     // Get the address\r
1639     //\r
1640     Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;\r
1641     VmWriteMemN (VmPtr, (UINTN) Op1, (INTN) ImmedIndex64);\r
1642   }\r
1643   //\r
1644   // Advance the instruction pointer\r
1645   //\r
1646   VmPtr->Ip += Size;\r
1647   return EFI_SUCCESS;\r
1648 }\r
1649 \r
1650 STATIC\r
1651 EFI_STATUS\r
1652 ExecuteMOVREL (\r
1653   IN VM_CONTEXT *VmPtr\r
1654   )\r
1655 /*++\r
1656 \r
1657 Routine Description:\r
1658   \r
1659   Execute the EBC MOVREL instruction.\r
1660   Dest <- Ip + ImmData\r
1661 \r
1662 Arguments:\r
1663 \r
1664   VmPtr   - pointer to a VM context  \r
1665 \r
1666 Returns:\r
1667 \r
1668   Standard EFI_STATUS\r
1669 \r
1670 Instruction syntax:\r
1671 \r
1672   MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64\r
1673 \r
1674 --*/\r
1675 {\r
1676   UINT8   Opcode;\r
1677   UINT8   Operands;\r
1678   UINT8   Size;\r
1679   INT16   Index16;\r
1680   INT64   ImmData64;\r
1681   UINT64  Op1;\r
1682   UINT64  Op2;\r
1683 \r
1684   //\r
1685   // Get the opcode and operands byte so we can get R1 and R2\r
1686   //\r
1687   Opcode    = GETOPCODE (VmPtr);\r
1688   Operands  = GETOPERANDS (VmPtr);\r
1689 \r
1690   //\r
1691   // Get the Operand 1 index (16-bit) if present\r
1692   //\r
1693   if (Operands & MOVI_M_IMMDATA) {\r
1694     Index16 = VmReadIndex16 (VmPtr, 2);\r
1695     Size    = 4;\r
1696   } else {\r
1697     Index16 = 0;\r
1698     Size    = 2;\r
1699   }\r
1700   //\r
1701   // Get the immediate data.\r
1702   //\r
1703   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {\r
1704     ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);\r
1705     Size += 2;\r
1706   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {\r
1707     ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);\r
1708     Size += 4;\r
1709   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {\r
1710     ImmData64 = VmReadImmed64 (VmPtr, Size);\r
1711     Size += 8;\r
1712   } else {\r
1713     //\r
1714     // Invalid encoding\r
1715     //\r
1716     EbcDebugSignalException (\r
1717       EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1718       EXCEPTION_FLAG_FATAL,\r
1719       VmPtr\r
1720       );\r
1721     return EFI_UNSUPPORTED;\r
1722   }\r
1723   //\r
1724   // Compute the value and write back the result\r
1725   //\r
1726   Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);\r
1727   if (!OPERAND1_INDIRECT (Operands)) {\r
1728     //\r
1729     // Check for illegal combination of operand1 direct with immediate data\r
1730     //\r
1731     if (Operands & MOVI_M_IMMDATA) {\r
1732       EbcDebugSignalException (\r
1733         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1734         EXCEPTION_FLAG_FATAL,\r
1735         VmPtr\r
1736         );\r
1737       return EFI_UNSUPPORTED;\r
1738     }\r
1739 \r
1740     VmPtr->R[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;\r
1741   } else {\r
1742     //\r
1743     // Get the address = [Rx] + Index16\r
1744     // Write back the result. Always a natural size write, since\r
1745     // we're talking addresses here.\r
1746     //\r
1747     Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;\r
1748     VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);\r
1749   }\r
1750   //\r
1751   // Advance the instruction pointer\r
1752   //\r
1753   VmPtr->Ip += Size;\r
1754   return EFI_SUCCESS;\r
1755 }\r
1756 \r
1757 STATIC\r
1758 EFI_STATUS\r
1759 ExecuteMOVsnw (\r
1760   IN VM_CONTEXT *VmPtr\r
1761   )\r
1762 /*++\r
1763 \r
1764 Routine Description:\r
1765   \r
1766   Execute the EBC MOVsnw instruction. This instruction loads a signed \r
1767   natural value from memory or register to another memory or register. On\r
1768   32-bit machines, the value gets sign-extended to 64 bits if the destination\r
1769   is a register.\r
1770 \r
1771 Arguments:\r
1772 \r
1773   VmPtr   - pointer to a VM context  \r
1774 \r
1775 Returns:\r
1776 \r
1777   Standard EFI_STATUS\r
1778 \r
1779 Instruction syntax:\r
1780 \r
1781   MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}\r
1782 \r
1783   0:7 1=>operand1 index present\r
1784   0:6 1=>operand2 index present\r
1785 \r
1786 --*/\r
1787 {\r
1788   UINT8   Opcode;\r
1789   UINT8   Operands;\r
1790   UINT8   Size;\r
1791   INT16   Op1Index;\r
1792   INT16   Op2Index;\r
1793   UINT64  Op2;\r
1794 \r
1795   //\r
1796   // Get the opcode and operand bytes\r
1797   //\r
1798   Opcode              = GETOPCODE (VmPtr);\r
1799   Operands            = GETOPERANDS (VmPtr);\r
1800 \r
1801   Op1Index            = Op2Index = 0;\r
1802 \r
1803   //\r
1804   // Get the indexes if present.\r
1805   //\r
1806   Size = 2;\r
1807   if (Opcode & OPCODE_M_IMMED_OP1) {\r
1808     if (OPERAND1_INDIRECT (Operands)) {\r
1809       Op1Index = VmReadIndex16 (VmPtr, 2);\r
1810     } else {\r
1811       //\r
1812       // Illegal form operand1 direct with index:  MOVsnw R1 Index16, {@}R2\r
1813       //\r
1814       EbcDebugSignalException (\r
1815         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1816         EXCEPTION_FLAG_FATAL,\r
1817         VmPtr\r
1818         );\r
1819       return EFI_UNSUPPORTED;\r
1820     }\r
1821 \r
1822     Size += sizeof (UINT16);\r
1823   }\r
1824 \r
1825   if (Opcode & OPCODE_M_IMMED_OP2) {\r
1826     if (OPERAND2_INDIRECT (Operands)) {\r
1827       Op2Index = VmReadIndex16 (VmPtr, Size);\r
1828     } else {\r
1829       Op2Index = VmReadImmed16 (VmPtr, Size);\r
1830     }\r
1831 \r
1832     Size += sizeof (UINT16);\r
1833   }\r
1834   //\r
1835   // Get the data from the source.\r
1836   //\r
1837   Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));\r
1838   if (OPERAND2_INDIRECT (Operands)) {\r
1839     Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);\r
1840   }\r
1841   //\r
1842   // Now write back the result.\r
1843   //\r
1844   if (!OPERAND1_INDIRECT (Operands)) {\r
1845     VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;\r
1846   } else {\r
1847     VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);\r
1848   }\r
1849   //\r
1850   // Advance the instruction pointer\r
1851   //\r
1852   VmPtr->Ip += Size;\r
1853   return EFI_SUCCESS;\r
1854 }\r
1855 \r
1856 STATIC\r
1857 EFI_STATUS\r
1858 ExecuteMOVsnd (\r
1859   IN VM_CONTEXT *VmPtr\r
1860   )\r
1861 /*++\r
1862 \r
1863 Routine Description:\r
1864   \r
1865   Execute the EBC MOVsnw instruction. This instruction loads a signed \r
1866   natural value from memory or register to another memory or register. On\r
1867   32-bit machines, the value gets sign-extended to 64 bits if the destination\r
1868   is a register.\r
1869 \r
1870 Arguments:\r
1871 \r
1872   VmPtr   - pointer to a VM context  \r
1873 \r
1874 Returns:\r
1875 \r
1876   Standard EFI_STATUS\r
1877 \r
1878 Instruction syntax:\r
1879 \r
1880   MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}\r
1881 \r
1882   0:7 1=>operand1 index present\r
1883   0:6 1=>operand2 index present\r
1884 \r
1885 --*/\r
1886 {\r
1887   UINT8   Opcode;\r
1888   UINT8   Operands;\r
1889   UINT8   Size;\r
1890   INT32   Op1Index;\r
1891   INT32   Op2Index;\r
1892   UINT64  Op2;\r
1893 \r
1894   //\r
1895   // Get the opcode and operand bytes\r
1896   //\r
1897   Opcode              = GETOPCODE (VmPtr);\r
1898   Operands            = GETOPERANDS (VmPtr);\r
1899 \r
1900   Op1Index            = Op2Index = 0;\r
1901 \r
1902   //\r
1903   // Get the indexes if present.\r
1904   //\r
1905   Size = 2;\r
1906   if (Opcode & OPCODE_M_IMMED_OP1) {\r
1907     if (OPERAND1_INDIRECT (Operands)) {\r
1908       Op1Index = VmReadIndex32 (VmPtr, 2);\r
1909     } else {\r
1910       //\r
1911       // Illegal form operand1 direct with index:  MOVsnd R1 Index16,..\r
1912       //\r
1913       EbcDebugSignalException (\r
1914         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
1915         EXCEPTION_FLAG_FATAL,\r
1916         VmPtr\r
1917         );\r
1918       return EFI_UNSUPPORTED;\r
1919     }\r
1920 \r
1921     Size += sizeof (UINT32);\r
1922   }\r
1923 \r
1924   if (Opcode & OPCODE_M_IMMED_OP2) {\r
1925     if (OPERAND2_INDIRECT (Operands)) {\r
1926       Op2Index = VmReadIndex32 (VmPtr, Size);\r
1927     } else {\r
1928       Op2Index = VmReadImmed32 (VmPtr, Size);\r
1929     }\r
1930 \r
1931     Size += sizeof (UINT32);\r
1932   }\r
1933   //\r
1934   // Get the data from the source.\r
1935   //\r
1936   Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));\r
1937   if (OPERAND2_INDIRECT (Operands)) {\r
1938     Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);\r
1939   }\r
1940   //\r
1941   // Now write back the result.\r
1942   //\r
1943   if (!OPERAND1_INDIRECT (Operands)) {\r
1944     VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;\r
1945   } else {\r
1946     VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);\r
1947   }\r
1948   //\r
1949   // Advance the instruction pointer\r
1950   //\r
1951   VmPtr->Ip += Size;\r
1952   return EFI_SUCCESS;\r
1953 }\r
1954 \r
1955 STATIC\r
1956 EFI_STATUS\r
1957 ExecutePUSHn (\r
1958   IN VM_CONTEXT *VmPtr\r
1959   )\r
1960 /*++\r
1961 \r
1962 Routine Description:\r
1963   Execute the EBC PUSHn instruction\r
1964 \r
1965 Arguments:\r
1966   VmPtr   - pointer to a VM context  \r
1967 \r
1968 Returns:\r
1969   Standard EFI_STATUS\r
1970 \r
1971 Instruction syntax:\r
1972    PUSHn {@}R1 {Index16|Immed16}\r
1973 \r
1974 --*/\r
1975 {\r
1976   UINT8 Opcode;\r
1977   UINT8 Operands;\r
1978   INT16 Index16;\r
1979   UINTN DataN;\r
1980 \r
1981   //\r
1982   // Get opcode and operands\r
1983   //\r
1984   Opcode    = GETOPCODE (VmPtr);\r
1985   Operands  = GETOPERANDS (VmPtr);\r
1986 \r
1987   //\r
1988   // Get index if present\r
1989   //\r
1990   if (Opcode & PUSHPOP_M_IMMDATA) {\r
1991     if (OPERAND1_INDIRECT (Operands)) {\r
1992       Index16 = VmReadIndex16 (VmPtr, 2);\r
1993     } else {\r
1994       Index16 = VmReadImmed16 (VmPtr, 2);\r
1995     }\r
1996 \r
1997     VmPtr->Ip += 4;\r
1998   } else {\r
1999     Index16 = 0;\r
2000     VmPtr->Ip += 2;\r
2001   }\r
2002   //\r
2003   // Get the data to push\r
2004   //\r
2005   if (OPERAND1_INDIRECT (Operands)) {\r
2006     DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));\r
2007   } else {\r
2008     DataN = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16);\r
2009   }\r
2010   //\r
2011   // Adjust the stack down.\r
2012   //\r
2013   VmPtr->R[0] -= sizeof (UINTN);\r
2014   VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], DataN);\r
2015   return EFI_SUCCESS;\r
2016 }\r
2017 \r
2018 STATIC\r
2019 EFI_STATUS\r
2020 ExecutePUSH (\r
2021   IN VM_CONTEXT *VmPtr\r
2022   )\r
2023 /*++\r
2024 \r
2025 Routine Description:\r
2026   Execute the EBC PUSH instruction\r
2027 \r
2028 Arguments:\r
2029   VmPtr   - pointer to a VM context  \r
2030 \r
2031 Returns:\r
2032   Standard EFI_STATUS\r
2033 \r
2034 Instruction syntax:\r
2035    PUSH[32|64] {@}R1 {Index16|Immed16}\r
2036 \r
2037 --*/\r
2038 {\r
2039   UINT8   Opcode;\r
2040   UINT8   Operands;\r
2041   UINT32  Data32;\r
2042   UINT64  Data64;\r
2043   INT16   Index16;\r
2044 \r
2045   //\r
2046   // Get opcode and operands\r
2047   //\r
2048   Opcode    = GETOPCODE (VmPtr);\r
2049   Operands  = GETOPERANDS (VmPtr);\r
2050   //\r
2051   // Get immediate index if present, then advance the IP.\r
2052   //\r
2053   if (Opcode & PUSHPOP_M_IMMDATA) {\r
2054     if (OPERAND1_INDIRECT (Operands)) {\r
2055       Index16 = VmReadIndex16 (VmPtr, 2);\r
2056     } else {\r
2057       Index16 = VmReadImmed16 (VmPtr, 2);\r
2058     }\r
2059 \r
2060     VmPtr->Ip += 4;\r
2061   } else {\r
2062     Index16 = 0;\r
2063     VmPtr->Ip += 2;\r
2064   }\r
2065   //\r
2066   // Get the data to push\r
2067   //\r
2068   if (Opcode & PUSHPOP_M_64) {\r
2069     if (OPERAND1_INDIRECT (Operands)) {\r
2070       Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));\r
2071     } else {\r
2072       Data64 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;\r
2073     }\r
2074     //\r
2075     // Adjust the stack down, then write back the data\r
2076     //\r
2077     VmPtr->R[0] -= sizeof (UINT64);\r
2078     VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], Data64);\r
2079   } else {\r
2080     //\r
2081     // 32-bit data\r
2082     //\r
2083     if (OPERAND1_INDIRECT (Operands)) {\r
2084       Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));\r
2085     } else {\r
2086       Data32 = (UINT32) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;\r
2087     }\r
2088     //\r
2089     // Adjust the stack down and write the data\r
2090     //\r
2091     VmPtr->R[0] -= sizeof (UINT32);\r
2092     VmWriteMem32 (VmPtr, (UINTN) VmPtr->R[0], Data32);\r
2093   }\r
2094 \r
2095   return EFI_SUCCESS;\r
2096 }\r
2097 \r
2098 STATIC\r
2099 EFI_STATUS\r
2100 ExecutePOPn (\r
2101   IN VM_CONTEXT *VmPtr\r
2102   )\r
2103 /*++\r
2104 \r
2105 Routine Description:\r
2106   Execute the EBC POPn instruction\r
2107 \r
2108 Arguments:\r
2109   VmPtr   - pointer to a VM context  \r
2110 \r
2111 Returns:\r
2112   Standard EFI_STATUS\r
2113 \r
2114 Instruction syntax:\r
2115    POPn {@}R1 {Index16|Immed16}\r
2116 \r
2117 --*/\r
2118 {\r
2119   UINT8 Opcode;\r
2120   UINT8 Operands;\r
2121   INT16 Index16;\r
2122   UINTN DataN;\r
2123 \r
2124   //\r
2125   // Get opcode and operands\r
2126   //\r
2127   Opcode    = GETOPCODE (VmPtr);\r
2128   Operands  = GETOPERANDS (VmPtr);\r
2129   //\r
2130   // Get immediate data if present, and advance the IP\r
2131   //\r
2132   if (Opcode & PUSHPOP_M_IMMDATA) {\r
2133     if (OPERAND1_INDIRECT (Operands)) {\r
2134       Index16 = VmReadIndex16 (VmPtr, 2);\r
2135     } else {\r
2136       Index16 = VmReadImmed16 (VmPtr, 2);\r
2137     }\r
2138 \r
2139     VmPtr->Ip += 4;\r
2140   } else {\r
2141     Index16 = 0;\r
2142     VmPtr->Ip += 2;\r
2143   }\r
2144   //\r
2145   // Read the data off the stack, then adjust the stack pointer\r
2146   //\r
2147   DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);\r
2148   VmPtr->R[0] += sizeof (UINTN);\r
2149   //\r
2150   // Do the write-back\r
2151   //\r
2152   if (OPERAND1_INDIRECT (Operands)) {\r
2153     VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), DataN);\r
2154   } else {\r
2155     VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16);\r
2156   }\r
2157 \r
2158   return EFI_SUCCESS;\r
2159 }\r
2160 \r
2161 STATIC\r
2162 EFI_STATUS\r
2163 ExecutePOP (\r
2164   IN VM_CONTEXT *VmPtr\r
2165   )\r
2166 /*++\r
2167 \r
2168 Routine Description:\r
2169   Execute the EBC POP instruction\r
2170 \r
2171 Arguments:\r
2172   VmPtr   - pointer to a VM context  \r
2173 \r
2174 Returns:\r
2175   Standard EFI_STATUS\r
2176 \r
2177 Instruction syntax:\r
2178   POP {@}R1 {Index16|Immed16}\r
2179 \r
2180 --*/\r
2181 {\r
2182   UINT8   Opcode;\r
2183   UINT8   Operands;\r
2184   INT16   Index16;\r
2185   INT32   Data32;\r
2186   UINT64  Data64;\r
2187 \r
2188   //\r
2189   // Get opcode and operands\r
2190   //\r
2191   Opcode    = GETOPCODE (VmPtr);\r
2192   Operands  = GETOPERANDS (VmPtr);\r
2193   //\r
2194   // Get immediate data if present, and advance the IP.\r
2195   //\r
2196   if (Opcode & PUSHPOP_M_IMMDATA) {\r
2197     if (OPERAND1_INDIRECT (Operands)) {\r
2198       Index16 = VmReadIndex16 (VmPtr, 2);\r
2199     } else {\r
2200       Index16 = VmReadImmed16 (VmPtr, 2);\r
2201     }\r
2202 \r
2203     VmPtr->Ip += 4;\r
2204   } else {\r
2205     Index16 = 0;\r
2206     VmPtr->Ip += 2;\r
2207   }\r
2208   //\r
2209   // Get the data off the stack, then write it to the appropriate location\r
2210   //\r
2211   if (Opcode & PUSHPOP_M_64) {\r
2212     //\r
2213     // Read the data off the stack, then adjust the stack pointer\r
2214     //\r
2215     Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);\r
2216     VmPtr->R[0] += sizeof (UINT64);\r
2217     //\r
2218     // Do the write-back\r
2219     //\r
2220     if (OPERAND1_INDIRECT (Operands)) {\r
2221       VmWriteMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data64);\r
2222     } else {\r
2223       VmPtr->R[OPERAND1_REGNUM (Operands)] = Data64 + Index16;\r
2224     }\r
2225   } else {\r
2226     //\r
2227     // 32-bit pop. Read it off the stack and adjust the stack pointer\r
2228     //\r
2229     Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->R[0]);\r
2230     VmPtr->R[0] += sizeof (UINT32);\r
2231     //\r
2232     // Do the write-back\r
2233     //\r
2234     if (OPERAND1_INDIRECT (Operands)) {\r
2235       VmWriteMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data32);\r
2236     } else {\r
2237       VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;\r
2238     }\r
2239   }\r
2240 \r
2241   return EFI_SUCCESS;\r
2242 }\r
2243 \r
2244 STATIC\r
2245 EFI_STATUS\r
2246 ExecuteCALL (\r
2247   IN VM_CONTEXT *VmPtr\r
2248   )\r
2249 /*++\r
2250 \r
2251 Routine Description:\r
2252   Implements the EBC CALL instruction.\r
2253 \r
2254   Instruction format:  \r
2255 \r
2256     CALL64 Immed64\r
2257     CALL32 {@}R1 {Immed32|Index32}\r
2258     CALLEX64 Immed64\r
2259     CALLEX16 {@}R1 {Immed32}\r
2260 \r
2261   If Rx == R0, then it's a PC relative call to PC = PC + imm32.\r
2262   \r
2263 Arguments:\r
2264   VmPtr - pointer to a VM context.\r
2265 \r
2266 Returns:\r
2267   Standard EFI_STATUS\r
2268 \r
2269 --*/\r
2270 {\r
2271   UINT8 Opcode;\r
2272   UINT8 Operands;\r
2273   INT32 Immed32;\r
2274   UINT8 Size;\r
2275   INT64 Immed64;\r
2276   VOID  *FramePtr;\r
2277 \r
2278   //\r
2279   // Get opcode and operands\r
2280   //\r
2281   Opcode    = GETOPCODE (VmPtr);\r
2282   Operands  = GETOPERANDS (VmPtr);\r
2283   //\r
2284   // Assign these as well to avoid compiler warnings\r
2285   //\r
2286   Immed64   = 0;\r
2287   Immed32   = 0;\r
2288 \r
2289   FramePtr  = VmPtr->FramePtr;\r
2290   //\r
2291   // Determine the instruction size, and get immediate data if present\r
2292   //\r
2293   if (Opcode & OPCODE_M_IMMDATA) {\r
2294     if (Opcode & OPCODE_M_IMMDATA64) {\r
2295       Immed64 = VmReadImmed64 (VmPtr, 2);\r
2296       Size    = 10;\r
2297     } else {\r
2298       //\r
2299       // If register operand is indirect, then the immediate data is an index\r
2300       //\r
2301       if (OPERAND1_INDIRECT (Operands)) {\r
2302         Immed32 = VmReadIndex32 (VmPtr, 2);\r
2303       } else {\r
2304         Immed32 = VmReadImmed32 (VmPtr, 2);\r
2305       }\r
2306 \r
2307       Size = 6;\r
2308     }\r
2309   } else {\r
2310     Size = 2;\r
2311   }\r
2312   //\r
2313   // If it's a call to EBC, adjust the stack pointer down 16 bytes and\r
2314   // put our return address and frame pointer on the VM stack.\r
2315   //\r
2316   if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
2317     VmPtr->R[0] -= 8;\r
2318     VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);\r
2319     VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];\r
2320     VmPtr->R[0] -= 8;\r
2321     VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (UINTN) (VmPtr->Ip + Size));\r
2322   }\r
2323   //\r
2324   // If 64-bit data, then absolute jump only\r
2325   //\r
2326   if (Opcode & OPCODE_M_IMMDATA64) {\r
2327     //\r
2328     // Native or EBC call?\r
2329     //\r
2330     if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
2331       VmPtr->Ip = (VMIP) (UINTN) Immed64;\r
2332     } else {\r
2333       //\r
2334       // Call external function, get the return value, and advance the IP\r
2335       //\r
2336       EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);\r
2337     }\r
2338   } else {\r
2339     //\r
2340     // Get the register data. If operand1 == 0, then ignore register and\r
2341     // take immediate data as relative or absolute address.\r
2342     // Compiler should take care of upper bits if 32-bit machine.\r
2343     //\r
2344     if (OPERAND1_REGNUM (Operands) != 0) {\r
2345       Immed64 = (UINT64) (UINTN) VmPtr->R[OPERAND1_REGNUM (Operands)];\r
2346     }\r
2347     //\r
2348     // Get final address\r
2349     //\r
2350     if (OPERAND1_INDIRECT (Operands)) {\r
2351       Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));\r
2352     } else {\r
2353       Immed64 += Immed32;\r
2354     }\r
2355     //\r
2356     // Now determine if external call, and then if relative or absolute\r
2357     //\r
2358     if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {\r
2359       //\r
2360       // EBC call. Relative or absolute? If relative, then it's relative to the\r
2361       // start of the next instruction.\r
2362       //\r
2363       if (Operands & OPERAND_M_RELATIVE_ADDR) {\r
2364         VmPtr->Ip += Immed64 + Size;\r
2365       } else {\r
2366         VmPtr->Ip = (VMIP) (UINTN) Immed64;\r
2367       }\r
2368     } else {\r
2369       //\r
2370       // Native call. Relative or absolute?\r
2371       //\r
2372       if (Operands & OPERAND_M_RELATIVE_ADDR) {\r
2373         EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->R[0], FramePtr, Size);\r
2374       } else {\r
2375         if (VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) {\r
2376           CpuBreakpoint ();\r
2377         }\r
2378 \r
2379         EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);\r
2380       }\r
2381     }\r
2382   }\r
2383 \r
2384   return EFI_SUCCESS;\r
2385 }\r
2386 \r
2387 STATIC\r
2388 EFI_STATUS\r
2389 ExecuteRET (\r
2390   IN VM_CONTEXT *VmPtr\r
2391   )\r
2392 /*++\r
2393 \r
2394 Routine Description:\r
2395   Execute the EBC RET instruction\r
2396 \r
2397 Arguments:\r
2398   VmPtr   - pointer to a VM context  \r
2399 \r
2400 Returns:\r
2401   Standard EFI_STATUS\r
2402 \r
2403 Instruction syntax:\r
2404    RET\r
2405 \r
2406 --*/\r
2407 {\r
2408   //\r
2409   // If we're at the top of the stack, then simply set the done\r
2410   // flag and return\r
2411   //\r
2412   if (VmPtr->StackRetAddr == (UINT64) VmPtr->R[0]) {\r
2413     VmPtr->StopFlags |= STOPFLAG_APP_DONE;\r
2414   } else {\r
2415     //\r
2416     // Pull the return address off the VM app's stack and set the IP\r
2417     // to it\r
2418     //\r
2419     if (!IS_ALIGNED ((UINTN) VmPtr->R[0], sizeof (UINT16))) {\r
2420       EbcDebugSignalException (\r
2421         EXCEPT_EBC_ALIGNMENT_CHECK,\r
2422         EXCEPTION_FLAG_FATAL,\r
2423         VmPtr\r
2424         );\r
2425     }\r
2426     //\r
2427     // Restore the IP and frame pointer from the stack\r
2428     //\r
2429     VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);\r
2430     VmPtr->R[0] += 8;\r
2431     VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);\r
2432     VmPtr->R[0] += 8;\r
2433   }\r
2434 \r
2435   return EFI_SUCCESS;\r
2436 }\r
2437 \r
2438 STATIC\r
2439 EFI_STATUS\r
2440 ExecuteCMP (\r
2441   IN VM_CONTEXT *VmPtr\r
2442   )\r
2443 /*++\r
2444 \r
2445 Routine Description:\r
2446   Execute the EBC CMP instruction\r
2447 \r
2448 Arguments:\r
2449   VmPtr   - pointer to a VM context  \r
2450 \r
2451 Returns:\r
2452   Standard EFI_STATUS\r
2453 \r
2454 Instruction syntax:\r
2455    CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}\r
2456 \r
2457 --*/\r
2458 {\r
2459   UINT8   Opcode;\r
2460   UINT8   Operands;\r
2461   UINT8   Size;\r
2462   INT16   Index16;\r
2463   UINT32  Flag;\r
2464   INT64   Op2;\r
2465   INT64   Op1;\r
2466 \r
2467   //\r
2468   // Get opcode and operands\r
2469   //\r
2470   Opcode    = GETOPCODE (VmPtr);\r
2471   Operands  = GETOPERANDS (VmPtr);\r
2472   //\r
2473   // Get the register data we're going to compare to\r
2474   //\r
2475   Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];\r
2476   //\r
2477   // Get immediate data\r
2478   //\r
2479   if (Opcode & OPCODE_M_IMMDATA) {\r
2480     if (OPERAND2_INDIRECT (Operands)) {\r
2481       Index16 = VmReadIndex16 (VmPtr, 2);\r
2482     } else {\r
2483       Index16 = VmReadImmed16 (VmPtr, 2);\r
2484     }\r
2485 \r
2486     Size = 4;\r
2487   } else {\r
2488     Index16 = 0;\r
2489     Size    = 2;\r
2490   }\r
2491   //\r
2492   // Now get Op2\r
2493   //\r
2494   if (OPERAND2_INDIRECT (Operands)) {\r
2495     if (Opcode & OPCODE_M_64BIT) {\r
2496       Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16));\r
2497     } else {\r
2498       //\r
2499       // 32-bit operations. 0-extend the values for all cases.\r
2500       //\r
2501       Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16)));\r
2502     }\r
2503   } else {\r
2504     Op2 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16;\r
2505   }\r
2506   //\r
2507   // Now do the compare\r
2508   //\r
2509   Flag = 0;\r
2510   if (Opcode & OPCODE_M_64BIT) {\r
2511     //\r
2512     // 64-bit compares\r
2513     //\r
2514     switch (Opcode & OPCODE_M_OPCODE) {\r
2515     case OPCODE_CMPEQ:\r
2516       if (Op1 == Op2) {\r
2517         Flag = 1;\r
2518       }\r
2519       break;\r
2520 \r
2521     case OPCODE_CMPLTE:\r
2522       if (Op1 <= Op2) {\r
2523         Flag = 1;\r
2524       }\r
2525       break;\r
2526 \r
2527     case OPCODE_CMPGTE:\r
2528       if (Op1 >= Op2) {\r
2529         Flag = 1;\r
2530       }\r
2531       break;\r
2532 \r
2533     case OPCODE_CMPULTE:\r
2534       if ((UINT64) Op1 <= (UINT64) Op2) {\r
2535         Flag = 1;\r
2536       }\r
2537       break;\r
2538 \r
2539     case OPCODE_CMPUGTE:\r
2540       if ((UINT64) Op1 >= (UINT64) Op2) {\r
2541         Flag = 1;\r
2542       }\r
2543       break;\r
2544 \r
2545     default:\r
2546       ASSERT (0);\r
2547     }\r
2548   } else {\r
2549     //\r
2550     // 32-bit compares\r
2551     //\r
2552     switch (Opcode & OPCODE_M_OPCODE) {\r
2553     case OPCODE_CMPEQ:\r
2554       if ((INT32) Op1 == (INT32) Op2) {\r
2555         Flag = 1;\r
2556       }\r
2557       break;\r
2558 \r
2559     case OPCODE_CMPLTE:\r
2560       if ((INT32) Op1 <= (INT32) Op2) {\r
2561         Flag = 1;\r
2562       }\r
2563       break;\r
2564 \r
2565     case OPCODE_CMPGTE:\r
2566       if ((INT32) Op1 >= (INT32) Op2) {\r
2567         Flag = 1;\r
2568       }\r
2569       break;\r
2570 \r
2571     case OPCODE_CMPULTE:\r
2572       if ((UINT32) Op1 <= (UINT32) Op2) {\r
2573         Flag = 1;\r
2574       }\r
2575       break;\r
2576 \r
2577     case OPCODE_CMPUGTE:\r
2578       if ((UINT32) Op1 >= (UINT32) Op2) {\r
2579         Flag = 1;\r
2580       }\r
2581       break;\r
2582 \r
2583     default:\r
2584       ASSERT (0);\r
2585     }\r
2586   }\r
2587   //\r
2588   // Now set the flag accordingly for the comparison\r
2589   //\r
2590   if (Flag) {\r
2591     VMFLAG_SET (VmPtr, VMFLAGS_CC);\r
2592   } else {\r
2593     VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);\r
2594   }\r
2595   //\r
2596   // Advance the IP\r
2597   //\r
2598   VmPtr->Ip += Size;\r
2599   return EFI_SUCCESS;\r
2600 }\r
2601 \r
2602 STATIC\r
2603 EFI_STATUS\r
2604 ExecuteCMPI (\r
2605   IN VM_CONTEXT *VmPtr\r
2606   )\r
2607 /*++\r
2608 \r
2609 Routine Description:\r
2610   Execute the EBC CMPI instruction\r
2611 \r
2612 Arguments:\r
2613   VmPtr   - pointer to a VM context  \r
2614 \r
2615 Returns:\r
2616   Standard EFI_STATUS\r
2617 \r
2618 Instruction syntax:\r
2619    CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32\r
2620 \r
2621 --*/\r
2622 {\r
2623   UINT8   Opcode;\r
2624   UINT8   Operands;\r
2625   UINT8   Size;\r
2626   INT64   Op1;\r
2627   INT64   Op2;\r
2628   INT16   Index16;\r
2629   UINT32  Flag;\r
2630 \r
2631   //\r
2632   // Get opcode and operands\r
2633   //\r
2634   Opcode    = GETOPCODE (VmPtr);\r
2635   Operands  = GETOPERANDS (VmPtr);\r
2636 \r
2637   //\r
2638   // Get operand1 index if present\r
2639   //\r
2640   Size = 2;\r
2641   if (Operands & OPERAND_M_CMPI_INDEX) {\r
2642     Index16 = VmReadIndex16 (VmPtr, 2);\r
2643     Size += 2;\r
2644   } else {\r
2645     Index16 = 0;\r
2646   }\r
2647   //\r
2648   // Get operand1 data we're going to compare to\r
2649   //\r
2650   Op1 = (INT64) VmPtr->R[OPERAND1_REGNUM (Operands)];\r
2651   if (OPERAND1_INDIRECT (Operands)) {\r
2652     //\r
2653     // Indirect operand1. Fetch 32 or 64-bit value based on compare size.\r
2654     //\r
2655     if (Opcode & OPCODE_M_CMPI64) {\r
2656       Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);\r
2657     } else {\r
2658       Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);\r
2659     }\r
2660   } else {\r
2661     //\r
2662     // Better not have been an index with direct. That is, CMPI R1 Index,...\r
2663     // is illegal.\r
2664     //\r
2665     if (Operands & OPERAND_M_CMPI_INDEX) {\r
2666       EbcDebugSignalException (\r
2667         EXCEPT_EBC_INSTRUCTION_ENCODING,\r
2668         EXCEPTION_FLAG_ERROR,\r
2669         VmPtr\r
2670         );\r
2671       VmPtr->Ip += Size;\r
2672       return EFI_UNSUPPORTED;\r
2673     }\r
2674   }\r
2675   //\r
2676   // Get immediate data -- 16- or 32-bit sign extended\r
2677   //\r
2678   if (Opcode & OPCODE_M_CMPI32_DATA) {\r
2679     Op2 = (INT64) VmReadImmed32 (VmPtr, Size);\r
2680     Size += 4;\r
2681   } else {\r
2682     //\r
2683     // 16-bit immediate data. Sign extend always.\r
2684     //\r
2685     Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));\r
2686     Size += 2;\r
2687   }\r
2688   //\r
2689   // Now do the compare\r
2690   //\r
2691   Flag = 0;\r
2692   if (Opcode & OPCODE_M_CMPI64) {\r
2693     //\r
2694     // 64 bit comparison\r
2695     //\r
2696     switch (Opcode & OPCODE_M_OPCODE) {\r
2697     case OPCODE_CMPIEQ:\r
2698       if (Op1 == (INT64) Op2) {\r
2699         Flag = 1;\r
2700       }\r
2701       break;\r
2702 \r
2703     case OPCODE_CMPILTE:\r
2704       if (Op1 <= (INT64) Op2) {\r
2705         Flag = 1;\r
2706       }\r
2707       break;\r
2708 \r
2709     case OPCODE_CMPIGTE:\r
2710       if (Op1 >= (INT64) Op2) {\r
2711         Flag = 1;\r
2712       }\r
2713       break;\r
2714 \r
2715     case OPCODE_CMPIULTE:\r
2716       if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {\r
2717         Flag = 1;\r
2718       }\r
2719       break;\r
2720 \r
2721     case OPCODE_CMPIUGTE:\r
2722       if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {\r
2723         Flag = 1;\r
2724       }\r
2725       break;\r
2726 \r
2727     default:\r
2728       ASSERT (0);\r
2729     }\r
2730   } else {\r
2731     //\r
2732     // 32-bit comparisons\r
2733     //\r
2734     switch (Opcode & OPCODE_M_OPCODE) {\r
2735     case OPCODE_CMPIEQ:\r
2736       if ((INT32) Op1 == Op2) {\r
2737         Flag = 1;\r
2738       }\r
2739       break;\r
2740 \r
2741     case OPCODE_CMPILTE:\r
2742       if ((INT32) Op1 <= Op2) {\r
2743         Flag = 1;\r
2744       }\r
2745       break;\r
2746 \r
2747     case OPCODE_CMPIGTE:\r
2748       if ((INT32) Op1 >= Op2) {\r
2749         Flag = 1;\r
2750       }\r
2751       break;\r
2752 \r
2753     case OPCODE_CMPIULTE:\r
2754       if ((UINT32) Op1 <= (UINT32) Op2) {\r
2755         Flag = 1;\r
2756       }\r
2757       break;\r
2758 \r
2759     case OPCODE_CMPIUGTE:\r
2760       if ((UINT32) Op1 >= (UINT32) Op2) {\r
2761         Flag = 1;\r
2762       }\r
2763       break;\r
2764 \r
2765     default:\r
2766       ASSERT (0);\r
2767     }\r
2768   }\r
2769   //\r
2770   // Now set the flag accordingly for the comparison\r
2771   //\r
2772   if (Flag) {\r
2773     VMFLAG_SET (VmPtr, VMFLAGS_CC);\r
2774   } else {\r
2775     VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);\r
2776   }\r
2777   //\r
2778   // Advance the IP\r
2779   //\r
2780   VmPtr->Ip += Size;\r
2781   return EFI_SUCCESS;\r
2782 }\r
2783 \r
2784 STATIC\r
2785 UINT64\r
2786 ExecuteNOT (\r
2787   IN VM_CONTEXT     *VmPtr,\r
2788   IN UINT64         Op1,\r
2789   IN UINT64         Op2\r
2790   )\r
2791 /*++\r
2792 \r
2793 Routine Description:\r
2794   Execute the EBC NOT instruction\r
2795 \r
2796 Arguments:\r
2797   VmPtr     - pointer to a VM context  \r
2798   Op1       - Operand 1 from the instruction \r
2799   Op2       - Operand 2 from the instruction\r
2800 \r
2801 Returns:\r
2802   ~Op2\r
2803 \r
2804 Instruction syntax:\r
2805   NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2806   \r
2807 --*/\r
2808 {\r
2809   return ~Op2;\r
2810 }\r
2811 \r
2812 STATIC\r
2813 UINT64\r
2814 ExecuteNEG (\r
2815   IN VM_CONTEXT   *VmPtr,\r
2816   IN UINT64       Op1,\r
2817   IN UINT64       Op2\r
2818   )\r
2819 /*++\r
2820 \r
2821 Routine Description:\r
2822   Execute the EBC NEG instruction\r
2823 \r
2824 Arguments:\r
2825   VmPtr     - pointer to a VM context  \r
2826   Op1       - Operand 1 from the instruction \r
2827   Op2       - Operand 2 from the instruction\r
2828 \r
2829 Returns:\r
2830   Op2 * -1\r
2831 \r
2832 Instruction syntax:\r
2833   NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2834 \r
2835 --*/\r
2836 {\r
2837   return ~Op2 + 1;\r
2838 }\r
2839 \r
2840 STATIC\r
2841 UINT64\r
2842 ExecuteADD (\r
2843   IN VM_CONTEXT   *VmPtr,\r
2844   IN UINT64       Op1,\r
2845   IN UINT64       Op2\r
2846   )\r
2847 /*++\r
2848 \r
2849 Routine Description:\r
2850   \r
2851   Execute the EBC ADD instruction\r
2852 \r
2853 Arguments:\r
2854   VmPtr     - pointer to a VM context  \r
2855   Op1       - Operand 1 from the instruction \r
2856   Op2       - Operand 2 from the instruction\r
2857 \r
2858 Returns:\r
2859   Op1 + Op2\r
2860 \r
2861 Instruction syntax:\r
2862    ADD[32|64] {@}R1, {@}R2 {Index16}\r
2863 \r
2864 --*/\r
2865 {\r
2866   return Op1 + Op2;\r
2867 }\r
2868 \r
2869 STATIC\r
2870 UINT64\r
2871 ExecuteSUB (\r
2872   IN VM_CONTEXT   *VmPtr,\r
2873   IN UINT64       Op1,\r
2874   IN UINT64       Op2\r
2875   )\r
2876 /*++\r
2877 \r
2878 Routine Description:\r
2879   Execute the EBC SUB instruction\r
2880 \r
2881 Arguments:\r
2882   VmPtr     - pointer to a VM context  \r
2883   Op1       - Operand 1 from the instruction \r
2884   Op2       - Operand 2 from the instruction\r
2885 \r
2886 Returns:\r
2887   Op1 - Op2\r
2888   Standard EFI_STATUS\r
2889 \r
2890 Instruction syntax:\r
2891   SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2892 \r
2893 --*/\r
2894 {\r
2895   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
2896     return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));\r
2897   } else {\r
2898     return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2));\r
2899   }\r
2900 }\r
2901 \r
2902 STATIC\r
2903 UINT64\r
2904 ExecuteMUL (\r
2905   IN VM_CONTEXT   *VmPtr,\r
2906   IN UINT64       Op1,\r
2907   IN UINT64       Op2\r
2908   )\r
2909 /*++\r
2910 \r
2911 Routine Description:\r
2912   \r
2913   Execute the EBC MUL instruction\r
2914 \r
2915 Arguments:\r
2916   VmPtr   - pointer to a VM context  \r
2917   Op1       - Operand 1 from the instruction \r
2918   Op2       - Operand 2 from the instruction\r
2919 \r
2920 Returns:\r
2921   Op1 * Op2\r
2922 \r
2923 Instruction syntax:\r
2924   MUL[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2925 \r
2926 --*/\r
2927 {\r
2928   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
2929     return MultS64x64 ((INT64)Op1, (INT64)Op2);\r
2930   } else {\r
2931     return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2));\r
2932   }\r
2933 }\r
2934 \r
2935 STATIC\r
2936 UINT64\r
2937 ExecuteMULU (\r
2938   IN VM_CONTEXT   *VmPtr,\r
2939   IN UINT64       Op1,\r
2940   IN UINT64       Op2\r
2941   )\r
2942 /*++\r
2943 \r
2944 Routine Description:\r
2945   Execute the EBC MULU instruction\r
2946 \r
2947 Arguments:\r
2948   VmPtr   - pointer to a VM context  \r
2949   Op1       - Operand 1 from the instruction \r
2950   Op2       - Operand 2 from the instruction\r
2951 \r
2952 Returns:\r
2953   (unsigned)Op1 * (unsigned)Op2 \r
2954 \r
2955 Instruction syntax:\r
2956   MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2957 \r
2958 --*/\r
2959 {\r
2960   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
2961     return MultU64x64 (Op1, Op2);\r
2962   } else {\r
2963     return (UINT64) ((UINT32) Op1 * (UINT32) Op2);\r
2964   }\r
2965 }\r
2966 \r
2967 STATIC\r
2968 UINT64\r
2969 ExecuteDIV (\r
2970   IN VM_CONTEXT   *VmPtr,\r
2971   IN UINT64       Op1,\r
2972   IN UINT64       Op2\r
2973   )\r
2974 /*++\r
2975 \r
2976 Routine Description:\r
2977   \r
2978   Execute the EBC DIV instruction\r
2979 \r
2980 Arguments:\r
2981   VmPtr     - pointer to a VM context  \r
2982   Op1       - Operand 1 from the instruction \r
2983   Op2       - Operand 2 from the instruction\r
2984 \r
2985 Returns:\r
2986   Op1/Op2\r
2987 \r
2988 Instruction syntax:\r
2989   DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
2990 \r
2991 --*/\r
2992 {\r
2993   INT64   Remainder;\r
2994 \r
2995   //\r
2996   // Check for divide-by-0\r
2997   //\r
2998   if (Op2 == 0) {\r
2999     EbcDebugSignalException (\r
3000       EXCEPT_EBC_DIVIDE_ERROR,\r
3001       EXCEPTION_FLAG_FATAL,\r
3002       VmPtr\r
3003       );\r
3004 \r
3005     return 0;\r
3006   } else {\r
3007     if (*VmPtr->Ip & DATAMANIP_M_64) {\r
3008       return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));\r
3009     } else {\r
3010       return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));\r
3011     }\r
3012   }\r
3013 }\r
3014 \r
3015 STATIC\r
3016 UINT64\r
3017 ExecuteDIVU (\r
3018   IN VM_CONTEXT   *VmPtr,\r
3019   IN UINT64       Op1,\r
3020   IN UINT64       Op2\r
3021   )\r
3022 /*++\r
3023 \r
3024 Routine Description:\r
3025   Execute the EBC DIVU instruction\r
3026 \r
3027 Arguments:\r
3028   VmPtr     - pointer to a VM context  \r
3029   Op1       - Operand 1 from the instruction \r
3030   Op2       - Operand 2 from the instruction\r
3031 \r
3032 Returns:\r
3033   (unsigned)Op1 / (unsigned)Op2\r
3034 \r
3035 Instruction syntax:\r
3036   DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3037 \r
3038 --*/\r
3039 {\r
3040   UINT64  Remainder;\r
3041 \r
3042   //\r
3043   // Check for divide-by-0\r
3044   //\r
3045   if (Op2 == 0) {\r
3046     EbcDebugSignalException (\r
3047       EXCEPT_EBC_DIVIDE_ERROR,\r
3048       EXCEPTION_FLAG_FATAL,\r
3049       VmPtr\r
3050       );\r
3051     return 0;\r
3052   } else {\r
3053     //\r
3054     // Get the destination register\r
3055     //\r
3056     if (*VmPtr->Ip & DATAMANIP_M_64) {\r
3057       return (UINT64) (DivU64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder));\r
3058     } else {\r
3059       return (UINT64) ((UINT32) Op1 / (UINT32) Op2);\r
3060     }\r
3061   }\r
3062 }\r
3063 \r
3064 STATIC\r
3065 UINT64\r
3066 ExecuteMOD (\r
3067   IN VM_CONTEXT   *VmPtr,\r
3068   IN UINT64       Op1,\r
3069   IN UINT64       Op2\r
3070   )\r
3071 /*++\r
3072 \r
3073 Routine Description:\r
3074   Execute the EBC MOD instruction\r
3075 \r
3076 Arguments:\r
3077   VmPtr     - pointer to a VM context  \r
3078   Op1       - Operand 1 from the instruction \r
3079   Op2       - Operand 2 from the instruction\r
3080 \r
3081 Returns:\r
3082   Op1 MODULUS Op2\r
3083 \r
3084 Instruction syntax:\r
3085   MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3086 \r
3087 --*/\r
3088 {\r
3089   INT64   Remainder;\r
3090 \r
3091   //\r
3092   // Check for divide-by-0\r
3093   //\r
3094   if (Op2 == 0) {\r
3095     EbcDebugSignalException (\r
3096       EXCEPT_EBC_DIVIDE_ERROR,\r
3097       EXCEPTION_FLAG_FATAL,\r
3098       VmPtr\r
3099       );\r
3100     return 0;\r
3101   } else {\r
3102     DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);\r
3103     return Remainder;\r
3104   }\r
3105 }\r
3106 \r
3107 STATIC\r
3108 UINT64\r
3109 ExecuteMODU (\r
3110   IN VM_CONTEXT   *VmPtr,\r
3111   IN UINT64       Op1,\r
3112   IN UINT64       Op2\r
3113   )\r
3114 /*++\r
3115 \r
3116 Routine Description:\r
3117   Execute the EBC MODU instruction\r
3118 \r
3119 Arguments:\r
3120   VmPtr     - pointer to a VM context  \r
3121   Op1       - Operand 1 from the instruction \r
3122   Op2       - Operand 2 from the instruction\r
3123 \r
3124 Returns:\r
3125   Op1 UNSIGNED_MODULUS Op2\r
3126 \r
3127 Instruction syntax:\r
3128   MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3129   \r
3130 --*/\r
3131 {\r
3132   UINT64  Remainder;\r
3133 \r
3134   //\r
3135   // Check for divide-by-0\r
3136   //\r
3137   if (Op2 == 0) {\r
3138     EbcDebugSignalException (\r
3139       EXCEPT_EBC_DIVIDE_ERROR,\r
3140       EXCEPTION_FLAG_FATAL,\r
3141       VmPtr\r
3142       );\r
3143     return 0;\r
3144   } else {\r
3145     DivU64x64Remainder (Op1, Op2, &Remainder);\r
3146     return Remainder;\r
3147   }\r
3148 }\r
3149 \r
3150 STATIC\r
3151 UINT64\r
3152 ExecuteAND (\r
3153   IN VM_CONTEXT   *VmPtr,\r
3154   IN UINT64       Op1,\r
3155   IN UINT64       Op2\r
3156   )\r
3157 /*++\r
3158 \r
3159 Routine Description:\r
3160   Execute the EBC AND instruction\r
3161 \r
3162 Arguments:\r
3163   VmPtr     - pointer to a VM context  \r
3164   Op1       - Operand 1 from the instruction \r
3165   Op2       - Operand 2 from the instruction\r
3166 \r
3167 Returns:\r
3168   Op1 AND Op2\r
3169 \r
3170 Instruction syntax:\r
3171   AND[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3172 \r
3173 --*/\r
3174 {\r
3175   return Op1 & Op2;\r
3176 }\r
3177 \r
3178 STATIC\r
3179 UINT64\r
3180 ExecuteOR (\r
3181   IN VM_CONTEXT   *VmPtr,\r
3182   IN UINT64       Op1,\r
3183   IN UINT64       Op2\r
3184   )\r
3185 /*++\r
3186 \r
3187 Routine Description:\r
3188   Execute the EBC OR instruction\r
3189 \r
3190 Arguments:\r
3191   VmPtr     - pointer to a VM context  \r
3192   Op1       - Operand 1 from the instruction \r
3193   Op2       - Operand 2 from the instruction\r
3194 \r
3195 Returns:\r
3196   Op1 OR Op2\r
3197 \r
3198 Instruction syntax:\r
3199   OR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3200 \r
3201 --*/\r
3202 {\r
3203   return Op1 | Op2;\r
3204 }\r
3205 \r
3206 STATIC\r
3207 UINT64\r
3208 ExecuteXOR (\r
3209   IN VM_CONTEXT   *VmPtr,\r
3210   IN UINT64       Op1,\r
3211   IN UINT64       Op2\r
3212   )\r
3213 /*++\r
3214 \r
3215 Routine Description:\r
3216   Execute the EBC XOR instruction\r
3217 \r
3218 Arguments:\r
3219   VmPtr     - pointer to a VM context  \r
3220   Op1       - Operand 1 from the instruction \r
3221   Op2       - Operand 2 from the instruction\r
3222 \r
3223 Returns:\r
3224   Op1 XOR Op2\r
3225 \r
3226 Instruction syntax:\r
3227   XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3228 \r
3229 --*/\r
3230 {\r
3231   return Op1 ^ Op2;\r
3232 }\r
3233 \r
3234 STATIC\r
3235 UINT64\r
3236 ExecuteSHL (\r
3237   IN VM_CONTEXT   *VmPtr,\r
3238   IN UINT64       Op1,\r
3239   IN UINT64       Op2\r
3240   )\r
3241 /*++\r
3242 \r
3243 Routine Description:\r
3244   \r
3245   Execute the EBC SHL shift left instruction\r
3246 \r
3247 Arguments:\r
3248   VmPtr     - pointer to a VM context  \r
3249   Op1       - Operand 1 from the instruction \r
3250   Op2       - Operand 2 from the instruction\r
3251 \r
3252 Returns:\r
3253   Op1 << Op2\r
3254 \r
3255 Instruction syntax:\r
3256   SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3257 \r
3258 --*/\r
3259 {\r
3260   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
3261     return LShiftU64 (Op1, (UINTN)Op2);\r
3262   } else {\r
3263     return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));\r
3264   }\r
3265 }\r
3266 \r
3267 STATIC\r
3268 UINT64\r
3269 ExecuteSHR (\r
3270   IN VM_CONTEXT   *VmPtr,\r
3271   IN UINT64       Op1,\r
3272   IN UINT64       Op2\r
3273   )\r
3274 /*++\r
3275 \r
3276 Routine Description:\r
3277   Execute the EBC SHR instruction\r
3278 \r
3279 Arguments:\r
3280   VmPtr     - pointer to a VM context  \r
3281   Op1       - Operand 1 from the instruction \r
3282   Op2       - Operand 2 from the instruction\r
3283 \r
3284 Returns:\r
3285   Op1 >> Op2  (unsigned operands)\r
3286 \r
3287 Instruction syntax:\r
3288   SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3289 \r
3290 --*/\r
3291 {\r
3292   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
3293     return RShiftU64 (Op1, (UINTN)Op2);\r
3294   } else {\r
3295     return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);\r
3296   }\r
3297 }\r
3298 \r
3299 STATIC\r
3300 UINT64\r
3301 ExecuteASHR (\r
3302   IN VM_CONTEXT   *VmPtr,\r
3303   IN UINT64       Op1,\r
3304   IN UINT64       Op2\r
3305   )\r
3306 /*++\r
3307 \r
3308 Routine Description:\r
3309   Execute the EBC ASHR instruction\r
3310 \r
3311 Arguments:\r
3312   VmPtr     - pointer to a VM context  \r
3313   Op1       - Operand 1 from the instruction \r
3314   Op2       - Operand 2 from the instruction\r
3315 \r
3316 Returns:\r
3317   Op1 >> Op2 (signed)\r
3318 \r
3319 Instruction syntax:\r
3320   ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3321 \r
3322 --*/\r
3323 {\r
3324   if (*VmPtr->Ip & DATAMANIP_M_64) {\r
3325     return ARShiftU64 (Op1, (UINTN)Op2);\r
3326   } else {\r
3327     return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));\r
3328   }\r
3329 }\r
3330 \r
3331 STATIC\r
3332 UINT64\r
3333 ExecuteEXTNDB (\r
3334   IN VM_CONTEXT   *VmPtr,\r
3335   IN UINT64       Op1,\r
3336   IN UINT64       Op2\r
3337   )\r
3338 /*++\r
3339 \r
3340 Routine Description:\r
3341   Execute the EBC EXTNDB instruction to sign-extend a byte value.\r
3342   \r
3343 Arguments:\r
3344   VmPtr     - pointer to a VM context  \r
3345   Op1       - Operand 1 from the instruction \r
3346   Op2       - Operand 2 from the instruction\r
3347 \r
3348 Returns:\r
3349   (INT64)(INT8)Op2\r
3350 \r
3351 Instruction syntax:\r
3352   EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3353 \r
3354   \r
3355 --*/\r
3356 {\r
3357   INT8  Data8;\r
3358   INT64 Data64;\r
3359   //\r
3360   // Convert to byte, then return as 64-bit signed value to let compiler\r
3361   // sign-extend the value\r
3362   //\r
3363   Data8   = (INT8) Op2;\r
3364   Data64  = (INT64) Data8;\r
3365 \r
3366   return (UINT64) Data64;\r
3367 }\r
3368 \r
3369 STATIC\r
3370 UINT64\r
3371 ExecuteEXTNDW (\r
3372   IN VM_CONTEXT   *VmPtr,\r
3373   IN UINT64       Op1,\r
3374   IN UINT64       Op2\r
3375   )\r
3376 /*++\r
3377 \r
3378 Routine Description:\r
3379   Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.\r
3380   \r
3381 Arguments:\r
3382   VmPtr     - pointer to a VM context  \r
3383   Op1       - Operand 1 from the instruction \r
3384   Op2       - Operand 2 from the instruction\r
3385 \r
3386 Returns:\r
3387   (INT64)(INT16)Op2\r
3388 \r
3389 Instruction syntax:\r
3390   EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3391 \r
3392   \r
3393 --*/\r
3394 {\r
3395   INT16 Data16;\r
3396   INT64 Data64;\r
3397   //\r
3398   // Convert to word, then return as 64-bit signed value to let compiler\r
3399   // sign-extend the value\r
3400   //\r
3401   Data16  = (INT16) Op2;\r
3402   Data64  = (INT64) Data16;\r
3403 \r
3404   return (UINT64) Data64;\r
3405 }\r
3406 //\r
3407 // Execute the EBC EXTNDD instruction.\r
3408 //\r
3409 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]\r
3410 //         EXTNDD Dest, Source\r
3411 //\r
3412 // Operation:  Dest <- SignExtended((DWORD)Source))\r
3413 //\r
3414 STATIC\r
3415 UINT64\r
3416 ExecuteEXTNDD (\r
3417   IN VM_CONTEXT   *VmPtr,\r
3418   IN UINT64       Op1,\r
3419   IN UINT64       Op2\r
3420   )\r
3421 /*++\r
3422 \r
3423 Routine Description:\r
3424   Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.\r
3425   \r
3426 Arguments:\r
3427   VmPtr     - pointer to a VM context  \r
3428   Op1       - Operand 1 from the instruction \r
3429   Op2       - Operand 2 from the instruction\r
3430 \r
3431 Returns:\r
3432   (INT64)(INT32)Op2\r
3433 \r
3434 Instruction syntax:\r
3435   EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}\r
3436 \r
3437   \r
3438 --*/\r
3439 {\r
3440   INT32 Data32;\r
3441   INT64 Data64;\r
3442   //\r
3443   // Convert to 32-bit value, then return as 64-bit signed value to let compiler\r
3444   // sign-extend the value\r
3445   //\r
3446   Data32  = (INT32) Op2;\r
3447   Data64  = (INT64) Data32;\r
3448 \r
3449   return (UINT64) Data64;\r
3450 }\r
3451 \r
3452 STATIC\r
3453 EFI_STATUS\r
3454 ExecuteSignedDataManip (\r
3455   IN VM_CONTEXT   *VmPtr\r
3456   )\r
3457 {\r
3458   //\r
3459   // Just call the data manipulation function with a flag indicating this\r
3460   // is a signed operation.\r
3461   //\r
3462   return ExecuteDataManip (VmPtr, TRUE);\r
3463 }\r
3464 \r
3465 STATIC\r
3466 EFI_STATUS\r
3467 ExecuteUnsignedDataManip (\r
3468   IN VM_CONTEXT   *VmPtr\r
3469   )\r
3470 {\r
3471   //\r
3472   // Just call the data manipulation function with a flag indicating this\r
3473   // is not a signed operation.\r
3474   //\r
3475   return ExecuteDataManip (VmPtr, FALSE);\r
3476 }\r
3477 \r
3478 STATIC\r
3479 EFI_STATUS\r
3480 ExecuteDataManip (\r
3481   IN VM_CONTEXT   *VmPtr,\r
3482   IN BOOLEAN      IsSignedOp\r
3483   )\r
3484 /*++\r
3485 \r
3486 Routine Description:\r
3487   Execute all the EBC data manipulation instructions. \r
3488   Since the EBC data manipulation instructions all have the same basic form, \r
3489   they can share the code that does the fetch of operands and the write-back\r
3490   of the result. This function performs the fetch of the operands (even if\r
3491   both are not needed to be fetched, like NOT instruction), dispatches to the\r
3492   appropriate subfunction, then writes back the returned result.\r
3493 \r
3494 Arguments:\r
3495   VmPtr - pointer to VM context\r
3496 \r
3497 Returns:\r
3498   Standard EBC status\r
3499 \r
3500 Format:  \r
3501   INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}\r
3502 \r
3503 --*/\r
3504 {\r
3505   UINT8   Opcode;\r
3506   INT16   Index16;\r
3507   UINT8   Operands;\r
3508   UINT8   Size;\r
3509   UINT64  Op1;\r
3510   UINT64  Op2;\r
3511 \r
3512   //\r
3513   // Get opcode and operands\r
3514   //\r
3515   Opcode    = GETOPCODE (VmPtr);\r
3516   Operands  = GETOPERANDS (VmPtr);\r
3517 \r
3518   //\r
3519   // Determine if we have immediate data by the opcode\r
3520   //\r
3521   if (Opcode & DATAMANIP_M_IMMDATA) {\r
3522     //\r
3523     // Index16 if Ry is indirect, or Immed16 if Ry direct.\r
3524     //\r
3525     if (OPERAND2_INDIRECT (Operands)) {\r
3526       Index16 = VmReadIndex16 (VmPtr, 2);\r
3527     } else {\r
3528       Index16 = VmReadImmed16 (VmPtr, 2);\r
3529     }\r
3530 \r
3531     Size = 4;\r
3532   } else {\r
3533     Index16 = 0;\r
3534     Size    = 2;\r
3535   }\r
3536   //\r
3537   // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}\r
3538   //\r
3539   Op2 = (UINT64) VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16;\r
3540   if (OPERAND2_INDIRECT (Operands)) {\r
3541     //\r
3542     // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data\r
3543     //\r
3544     if (Opcode & DATAMANIP_M_64) {\r
3545       Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);\r
3546     } else {\r
3547       //\r
3548       // Read as signed value where appropriate.\r
3549       //\r
3550       if (IsSignedOp) {\r
3551         Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));\r
3552       } else {\r
3553         Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);\r
3554       }\r
3555     }\r
3556   } else {\r
3557     if ((Opcode & DATAMANIP_M_64) == 0) {\r
3558       if (IsSignedOp) {\r
3559         Op2 = (UINT64) (INT64) ((INT32) Op2);\r
3560       } else {\r
3561         Op2 = (UINT64) ((UINT32) Op2);\r
3562       }\r
3563     }\r
3564   }\r
3565   //\r
3566   // Get operand1 (destination and sometimes also an actual operand)\r
3567   // of form {@}R1\r
3568   //\r
3569   Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];\r
3570   if (OPERAND1_INDIRECT (Operands)) {\r
3571     if (Opcode & DATAMANIP_M_64) {\r
3572       Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);\r
3573     } else {\r
3574       if (IsSignedOp) {\r
3575         Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));\r
3576       } else {\r
3577         Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);\r
3578       }\r
3579     }\r
3580   } else {\r
3581     if ((Opcode & DATAMANIP_M_64) == 0) {\r
3582       if (IsSignedOp) {\r
3583         Op1 = (UINT64) (INT64) ((INT32) Op1);\r
3584       } else {\r
3585         Op1 = (UINT64) ((UINT32) Op1);\r
3586       }\r
3587     }\r
3588   }\r
3589   //\r
3590   // Dispatch to the computation function\r
3591   //\r
3592   if (((Opcode & OPCODE_M_OPCODE) - OPCODE_NOT) >=\r
3593         (sizeof (mDataManipDispatchTable) / sizeof (mDataManipDispatchTable[0]))\r
3594         ) {\r