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