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