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