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