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