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