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