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