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