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