]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/EbcDxe/EbcExecute.c
Update to fix minor coding style issues.
[mirror_edk2.git] / MdeModulePkg / Universal / EbcDxe / EbcExecute.c
1 /** @file
2 Contains code that implements the virtual machine.
3
4 Copyright (c) 2006 - 2008, 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 adress.
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 adress.
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 adress.
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 adress.
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 Adddress 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 Adddress 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 Adddress 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 unsinged 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 unsinged 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 unsinged 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 STATIC 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 STATIC 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 };
1335
1336 //
1337 // Length of JMP instructions, depending on upper two bits of opcode.
1338 //
1339 STATIC CONST UINT8 mJMPLen[] = { 2, 2, 6, 10 };
1340
1341 //
1342 // Simple Debugger Protocol GUID
1343 //
1344 EFI_GUID mEbcSimpleDebuggerProtocolGuid = EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID;
1345
1346
1347 /**
1348 Given a pointer to a new VM context, execute one or more instructions. This
1349 function is only used for test purposes via the EBC VM test protocol.
1350
1351 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1352 @param VmPtr A pointer to a VM context.
1353 @param InstructionCount A pointer to a UINTN value holding the number of
1354 instructions to execute. If it holds value of 0,
1355 then the instruction to be executed is 1.
1356
1357 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1358 @retval EFI_SUCCESS All of the instructions are executed successfully.
1359
1360 **/
1361 EFI_STATUS
1362 EbcExecuteInstructions (
1363 IN EFI_EBC_VM_TEST_PROTOCOL *This,
1364 IN VM_CONTEXT *VmPtr,
1365 IN OUT UINTN *InstructionCount
1366 )
1367 {
1368 UINTN ExecFunc;
1369 EFI_STATUS Status;
1370 UINTN InstructionsLeft;
1371 UINTN SavedInstructionCount;
1372
1373 Status = EFI_SUCCESS;
1374
1375 if (*InstructionCount == 0) {
1376 InstructionsLeft = 1;
1377 } else {
1378 InstructionsLeft = *InstructionCount;
1379 }
1380
1381 SavedInstructionCount = *InstructionCount;
1382 *InstructionCount = 0;
1383
1384 //
1385 // Index into the opcode table using the opcode byte for this instruction.
1386 // This gives you the execute function, which we first test for null, then
1387 // call it if it's not null.
1388 //
1389 while (InstructionsLeft != 0) {
1390 ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & 0x3F)].ExecuteFunction;
1391 if (ExecFunc == (UINTN) NULL) {
1392 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
1393 return EFI_UNSUPPORTED;
1394 } else {
1395 mVmOpcodeTable[(*VmPtr->Ip & 0x3F)].ExecuteFunction (VmPtr);
1396 *InstructionCount = *InstructionCount + 1;
1397 }
1398
1399 //
1400 // Decrement counter if applicable
1401 //
1402 if (SavedInstructionCount != 0) {
1403 InstructionsLeft--;
1404 }
1405 }
1406
1407 return Status;
1408 }
1409
1410
1411 /**
1412 Execute an EBC image from an entry point or from a published protocol.
1413
1414 @param VmPtr A pointer to a VM context.
1415
1416 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1417 @retval EFI_SUCCESS All of the instructions are executed successfully.
1418
1419 **/
1420 EFI_STATUS
1421 EbcExecute (
1422 IN VM_CONTEXT *VmPtr
1423 )
1424 {
1425 UINTN ExecFunc;
1426 UINT8 StackCorrupted;
1427 EFI_STATUS Status;
1428 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *EbcSimpleDebugger;
1429
1430 mVmPtr = VmPtr;
1431 EbcSimpleDebugger = NULL;
1432 Status = EFI_SUCCESS;
1433 StackCorrupted = 0;
1434
1435 //
1436 // Make sure the magic value has been put on the stack before we got here.
1437 //
1438 if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {
1439 StackCorrupted = 1;
1440 }
1441
1442 VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->R[0] + 8);
1443
1444 //
1445 // Try to get the debug support for EBC
1446 //
1447 DEBUG_CODE_BEGIN ();
1448 Status = gBS->LocateProtocol (
1449 &mEbcSimpleDebuggerProtocolGuid,
1450 NULL,
1451 (VOID **) &EbcSimpleDebugger
1452 );
1453 if (EFI_ERROR (Status)) {
1454 EbcSimpleDebugger = NULL;
1455 }
1456 DEBUG_CODE_END ();
1457
1458 //
1459 // Save the start IP for debug. For example, if we take an exception we
1460 // can print out the location of the exception relative to the entry point,
1461 // which could then be used in a disassembly listing to find the problem.
1462 //
1463 VmPtr->EntryPoint = (VOID *) VmPtr->Ip;
1464
1465 //
1466 // We'll wait for this flag to know when we're done. The RET
1467 // instruction sets it if it runs out of stack.
1468 //
1469 VmPtr->StopFlags = 0;
1470 while ((VmPtr->StopFlags & STOPFLAG_APP_DONE) == 0) {
1471 //
1472 // If we've found a simple debugger protocol, call it
1473 //
1474 DEBUG_CODE_BEGIN ();
1475 if (EbcSimpleDebugger != NULL) {
1476 EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);
1477 }
1478 DEBUG_CODE_END ();
1479
1480 //
1481 // Verify the opcode is in range. Otherwise generate an exception.
1482 //
1483 if ((*VmPtr->Ip & OPCODE_M_OPCODE) >= (sizeof (mVmOpcodeTable) / sizeof (mVmOpcodeTable[0]))) {
1484 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
1485 Status = EFI_UNSUPPORTED;
1486 goto Done;
1487 }
1488 //
1489 // Use the opcode bits to index into the opcode dispatch table. If the
1490 // function pointer is null then generate an exception.
1491 //
1492 ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
1493 if (ExecFunc == (UINTN) NULL) {
1494 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
1495 Status = EFI_UNSUPPORTED;
1496 goto Done;
1497 }
1498 //
1499 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1500 // and after each instruction is executed.
1501 //
1502 MemoryFence ();
1503
1504 mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
1505
1506 MemoryFence ();
1507
1508 //
1509 // If the step flag is set, signal an exception and continue. We don't
1510 // clear it here. Assuming the debugger is responsible for clearing it.
1511 //
1512 if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {
1513 EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);
1514 }
1515 //
1516 // Make sure stack has not been corrupted. Only report it once though.
1517 //
1518 if ((StackCorrupted == 0) && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {
1519 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
1520 StackCorrupted = 1;
1521 }
1522 if ((StackCorrupted == 0) && ((UINT64)VmPtr->R[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {
1523 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
1524 StackCorrupted = 1;
1525 }
1526 }
1527
1528 Done:
1529 mVmPtr = NULL;
1530
1531 return Status;
1532 }
1533
1534
1535 /**
1536 Execute the MOVxx instructions.
1537
1538 Instruction format:
1539
1540 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1541 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1542
1543 Copies contents of [R2] -> [R1], zero extending where required.
1544
1545 First character indicates the size of the move.
1546 Second character indicates the size of the index(s).
1547
1548 Invalid to have R1 direct with index.
1549
1550 @param VmPtr A pointer to a VM context.
1551
1552 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1553 @retval EFI_SUCCESS The instruction is executed successfully.
1554
1555 **/
1556 EFI_STATUS
1557 ExecuteMOVxx (
1558 IN VM_CONTEXT *VmPtr
1559 )
1560 {
1561 UINT8 Opcode;
1562 UINT8 OpcMasked;
1563 UINT8 Operands;
1564 UINT8 Size;
1565 UINT8 MoveSize;
1566 INT16 Index16;
1567 INT32 Index32;
1568 INT64 Index64Op1;
1569 INT64 Index64Op2;
1570 UINT64 Data64;
1571 UINT64 DataMask;
1572 UINTN Source;
1573
1574 Opcode = GETOPCODE (VmPtr);
1575 OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);
1576
1577 //
1578 // Get the operands byte so we can get R1 and R2
1579 //
1580 Operands = GETOPERANDS (VmPtr);
1581
1582 //
1583 // Assume no indexes
1584 //
1585 Index64Op1 = 0;
1586 Index64Op2 = 0;
1587 Data64 = 0;
1588
1589 //
1590 // Determine if we have an index/immediate data. Base instruction size
1591 // is 2 (opcode + operands). Add to this size each index specified.
1592 //
1593 Size = 2;
1594 if ((Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
1595 //
1596 // Determine size of the index from the opcode. Then get it.
1597 //
1598 if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {
1599 //
1600 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1601 // Get one or both index values.
1602 //
1603 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
1604 Index16 = VmReadIndex16 (VmPtr, 2);
1605 Index64Op1 = (INT64) Index16;
1606 Size += sizeof (UINT16);
1607 }
1608
1609 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
1610 Index16 = VmReadIndex16 (VmPtr, Size);
1611 Index64Op2 = (INT64) Index16;
1612 Size += sizeof (UINT16);
1613 }
1614 } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {
1615 //
1616 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1617 //
1618 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
1619 Index32 = VmReadIndex32 (VmPtr, 2);
1620 Index64Op1 = (INT64) Index32;
1621 Size += sizeof (UINT32);
1622 }
1623
1624 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
1625 Index32 = VmReadIndex32 (VmPtr, Size);
1626 Index64Op2 = (INT64) Index32;
1627 Size += sizeof (UINT32);
1628 }
1629 } else if (OpcMasked == OPCODE_MOVQQ) {
1630 //
1631 // MOVqq -- only form with a 64-bit index
1632 //
1633 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
1634 Index64Op1 = VmReadIndex64 (VmPtr, 2);
1635 Size += sizeof (UINT64);
1636 }
1637
1638 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
1639 Index64Op2 = VmReadIndex64 (VmPtr, Size);
1640 Size += sizeof (UINT64);
1641 }
1642 } else {
1643 //
1644 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1645 //
1646 EbcDebugSignalException (
1647 EXCEPT_EBC_INSTRUCTION_ENCODING,
1648 EXCEPTION_FLAG_FATAL,
1649 VmPtr
1650 );
1651 return EFI_UNSUPPORTED;
1652 }
1653 }
1654 //
1655 // Determine the size of the move, and create a mask for it so we can
1656 // clear unused bits.
1657 //
1658 if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {
1659 MoveSize = DATA_SIZE_8;
1660 DataMask = 0xFF;
1661 } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {
1662 MoveSize = DATA_SIZE_16;
1663 DataMask = 0xFFFF;
1664 } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {
1665 MoveSize = DATA_SIZE_32;
1666 DataMask = 0xFFFFFFFF;
1667 } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {
1668 MoveSize = DATA_SIZE_64;
1669 DataMask = (UINT64)~0;
1670 } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {
1671 MoveSize = DATA_SIZE_N;
1672 DataMask = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));
1673 } else {
1674 //
1675 // We were dispatched to this function and we don't recognize the opcode
1676 //
1677 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);
1678 return EFI_UNSUPPORTED;
1679 }
1680 //
1681 // Now get the source address
1682 //
1683 if (OPERAND2_INDIRECT (Operands)) {
1684 //
1685 // Indirect form @R2. Compute address of operand2
1686 //
1687 Source = (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index64Op2);
1688 //
1689 // Now get the data from the source. Always 0-extend and let the compiler
1690 // sign-extend where required.
1691 //
1692 switch (MoveSize) {
1693 case DATA_SIZE_8:
1694 Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);
1695 break;
1696
1697 case DATA_SIZE_16:
1698 Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);
1699 break;
1700
1701 case DATA_SIZE_32:
1702 Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);
1703 break;
1704
1705 case DATA_SIZE_64:
1706 Data64 = (UINT64) VmReadMem64 (VmPtr, Source);
1707 break;
1708
1709 case DATA_SIZE_N:
1710 Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);
1711 break;
1712
1713 default:
1714 //
1715 // not reached
1716 //
1717 break;
1718 }
1719 } else {
1720 //
1721 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1722 //
1723 Data64 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index64Op2;
1724 //
1725 // Did Operand2 have an index? If so, treat as two signed values since
1726 // indexes are signed values.
1727 //
1728 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
1729 //
1730 // NOTE: need to find a way to fix this, most likely by changing the VM
1731 // implementation to remove the stack gap. To do that, we'd need to
1732 // allocate stack space for the VM and actually set the system
1733 // stack pointer to the allocated buffer when the VM starts.
1734 //
1735 // Special case -- if someone took the address of a function parameter
1736 // then we need to make sure it's not in the stack gap. We can identify
1737 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1738 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1739 // Situations that to be aware of:
1740 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1741 //
1742 if ((OPERAND2_REGNUM (Operands) == 0) &&
1743 (!OPERAND2_INDIRECT (Operands)) &&
1744 (Index64Op2 > 0) &&
1745 (OPERAND1_REGNUM (Operands) == 0) &&
1746 (OPERAND1_INDIRECT (Operands))
1747 ) {
1748 Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);
1749 }
1750 }
1751 }
1752 //
1753 // Now write it back
1754 //
1755 if (OPERAND1_INDIRECT (Operands)) {
1756 //
1757 // Reuse the Source variable to now be dest.
1758 //
1759 Source = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index64Op1);
1760 //
1761 // Do the write based on the size
1762 //
1763 switch (MoveSize) {
1764 case DATA_SIZE_8:
1765 VmWriteMem8 (VmPtr, Source, (UINT8) Data64);
1766 break;
1767
1768 case DATA_SIZE_16:
1769 VmWriteMem16 (VmPtr, Source, (UINT16) Data64);
1770 break;
1771
1772 case DATA_SIZE_32:
1773 VmWriteMem32 (VmPtr, Source, (UINT32) Data64);
1774 break;
1775
1776 case DATA_SIZE_64:
1777 VmWriteMem64 (VmPtr, Source, Data64);
1778 break;
1779
1780 case DATA_SIZE_N:
1781 VmWriteMemN (VmPtr, Source, (UINTN) Data64);
1782 break;
1783
1784 default:
1785 //
1786 // not reached
1787 //
1788 break;
1789 }
1790 } else {
1791 //
1792 // Operand1 direct.
1793 // Make sure we didn't have an index on operand1.
1794 //
1795 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
1796 EbcDebugSignalException (
1797 EXCEPT_EBC_INSTRUCTION_ENCODING,
1798 EXCEPTION_FLAG_FATAL,
1799 VmPtr
1800 );
1801 return EFI_UNSUPPORTED;
1802 }
1803 //
1804 // Direct storage in register. Clear unused bits and store back to
1805 // register.
1806 //
1807 VmPtr->R[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;
1808 }
1809 //
1810 // Advance the instruction pointer
1811 //
1812 VmPtr->Ip += Size;
1813 return EFI_SUCCESS;
1814 }
1815
1816
1817 /**
1818 Execute the EBC BREAK instruction.
1819
1820 @param VmPtr A pointer to a VM context.
1821
1822 @retval EFI_SUCCESS The instruction is executed successfully.
1823
1824 **/
1825 EFI_STATUS
1826 ExecuteBREAK (
1827 IN VM_CONTEXT *VmPtr
1828 )
1829 {
1830 UINT8 Operands;
1831 VOID *EbcEntryPoint;
1832 VOID *Thunk;
1833 UINT64 U64EbcEntryPoint;
1834 INT32 Offset;
1835
1836 Operands = GETOPERANDS (VmPtr);
1837 switch (Operands) {
1838 //
1839 // Runaway program break. Generate an exception and terminate
1840 //
1841 case 0:
1842 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
1843 break;
1844
1845 //
1846 // Get VM version -- return VM revision number in R7
1847 //
1848 case 1:
1849 //
1850 // Bits:
1851 // 63-17 = 0
1852 // 16-8 = Major version
1853 // 7-0 = Minor version
1854 //
1855 VmPtr->R[7] = GetVmVersion ();
1856 break;
1857
1858 //
1859 // Debugger breakpoint
1860 //
1861 case 3:
1862 VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;
1863 //
1864 // See if someone has registered a handler
1865 //
1866 EbcDebugSignalException (
1867 EXCEPT_EBC_BREAKPOINT,
1868 EXCEPTION_FLAG_NONE,
1869 VmPtr
1870 );
1871 break;
1872
1873 //
1874 // System call, which there are none, so NOP it.
1875 //
1876 case 4:
1877 break;
1878
1879 //
1880 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1881 // "offset from self" pointer to the EBC entry point.
1882 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1883 //
1884 case 5:
1885 Offset = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->R[7]);
1886 U64EbcEntryPoint = (UINT64) (VmPtr->R[7] + Offset + 4);
1887 EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint;
1888
1889 //
1890 // Now create a new thunk
1891 //
1892 EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);
1893
1894 //
1895 // Finally replace the EBC entry point memory with the thunk address
1896 //
1897 VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[7], (UINT64) (UINTN) Thunk);
1898 break;
1899
1900 //
1901 // Compiler setting version per value in R7
1902 //
1903 case 6:
1904 VmPtr->CompilerVersion = (UINT32) VmPtr->R[7];
1905 //
1906 // Check compiler version against VM version?
1907 //
1908 break;
1909
1910 //
1911 // Unhandled break code. Signal exception.
1912 //
1913 default:
1914 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
1915 break;
1916 }
1917 //
1918 // Advance IP
1919 //
1920 VmPtr->Ip += 2;
1921 return EFI_SUCCESS;
1922 }
1923
1924
1925 /**
1926 Execute the JMP instruction.
1927
1928 Instruction syntax:
1929 JMP64{cs|cc} Immed64
1930 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1931
1932 Encoding:
1933 b0.7 - immediate data present
1934 b0.6 - 1 = 64 bit immediate data
1935 0 = 32 bit immediate data
1936 b1.7 - 1 = conditional
1937 b1.6 1 = CS (condition set)
1938 0 = CC (condition clear)
1939 b1.4 1 = relative address
1940 0 = absolute address
1941 b1.3 1 = operand1 indirect
1942 b1.2-0 operand 1
1943
1944 @param VmPtr A pointer to a VM context.
1945
1946 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1947 @retval EFI_SUCCESS The instruction is executed successfully.
1948
1949 **/
1950 EFI_STATUS
1951 ExecuteJMP (
1952 IN VM_CONTEXT *VmPtr
1953 )
1954 {
1955 UINT8 Opcode;
1956 UINT8 CompareSet;
1957 UINT8 ConditionFlag;
1958 UINT8 Size;
1959 UINT8 Operand;
1960 UINT64 Data64;
1961 INT32 Index32;
1962 UINTN Addr;
1963
1964 Operand = GETOPERANDS (VmPtr);
1965 Opcode = GETOPCODE (VmPtr);
1966
1967 //
1968 // Get instruction length from the opcode. The upper two bits are used here
1969 // to index into the length array.
1970 //
1971 Size = mJMPLen[(Opcode >> 6) & 0x03];
1972
1973 //
1974 // Decode instruction conditions
1975 // If we haven't met the condition, then simply advance the IP and return.
1976 //
1977 CompareSet = (UINT8) (((Operand & JMP_M_CS) != 0) ? 1 : 0);
1978 ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
1979 if ((Operand & CONDITION_M_CONDITIONAL) != 0) {
1980 if (CompareSet != ConditionFlag) {
1981 VmPtr->Ip += Size;
1982 return EFI_SUCCESS;
1983 }
1984 }
1985 //
1986 // Check for 64-bit form and do it right away since it's the most
1987 // straight-forward form.
1988 //
1989 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
1990 //
1991 // Double check for immediate-data, which is required. If not there,
1992 // then signal an exception
1993 //
1994 if ((Opcode & OPCODE_M_IMMDATA) == 0) {
1995 EbcDebugSignalException (
1996 EXCEPT_EBC_INSTRUCTION_ENCODING,
1997 EXCEPTION_FLAG_ERROR,
1998 VmPtr
1999 );
2000 return EFI_UNSUPPORTED;
2001 }
2002 //
2003 // 64-bit immediate data is full address. Read the immediate data,
2004 // check for alignment, and jump absolute.
2005 //
2006 Data64 = VmReadImmed64 (VmPtr, 2);
2007 if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
2008 EbcDebugSignalException (
2009 EXCEPT_EBC_ALIGNMENT_CHECK,
2010 EXCEPTION_FLAG_FATAL,
2011 VmPtr
2012 );
2013
2014 return EFI_UNSUPPORTED;
2015 }
2016
2017 //
2018 // Take jump -- relative or absolute
2019 //
2020 if ((Operand & JMP_M_RELATIVE) != 0) {
2021 VmPtr->Ip += (UINTN) Data64 + Size;
2022 } else {
2023 VmPtr->Ip = (VMIP) (UINTN) Data64;
2024 }
2025
2026 return EFI_SUCCESS;
2027 }
2028 //
2029 // 32-bit forms:
2030 // Get the index if there is one. May be either an index, or an immediate
2031 // offset depending on indirect operand.
2032 // JMP32 @R1 Index32 -- immediate data is an index
2033 // JMP32 R1 Immed32 -- immedate data is an offset
2034 //
2035 if ((Opcode & OPCODE_M_IMMDATA) != 0) {
2036 if (OPERAND1_INDIRECT (Operand)) {
2037 Index32 = VmReadIndex32 (VmPtr, 2);
2038 } else {
2039 Index32 = VmReadImmed32 (VmPtr, 2);
2040 }
2041 } else {
2042 Index32 = 0;
2043 }
2044 //
2045 // Get the register data. If R == 0, then special case where it's ignored.
2046 //
2047 if (OPERAND1_REGNUM (Operand) == 0) {
2048 Data64 = 0;
2049 } else {
2050 Data64 = OPERAND1_REGDATA (VmPtr, Operand);
2051 }
2052 //
2053 // Decode the forms
2054 //
2055 if (OPERAND1_INDIRECT (Operand)) {
2056 //
2057 // Form: JMP32 @Rx {Index32}
2058 //
2059 Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
2060 if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
2061 EbcDebugSignalException (
2062 EXCEPT_EBC_ALIGNMENT_CHECK,
2063 EXCEPTION_FLAG_FATAL,
2064 VmPtr
2065 );
2066
2067 return EFI_UNSUPPORTED;
2068 }
2069
2070 if ((Operand & JMP_M_RELATIVE) != 0) {
2071 VmPtr->Ip += (UINTN) Addr + Size;
2072 } else {
2073 VmPtr->Ip = (VMIP) Addr;
2074 }
2075 } else {
2076 //
2077 // Form: JMP32 Rx {Immed32}
2078 //
2079 Addr = (UINTN) (Data64 + Index32);
2080 if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
2081 EbcDebugSignalException (
2082 EXCEPT_EBC_ALIGNMENT_CHECK,
2083 EXCEPTION_FLAG_FATAL,
2084 VmPtr
2085 );
2086
2087 return EFI_UNSUPPORTED;
2088 }
2089
2090 if ((Operand & JMP_M_RELATIVE) != 0) {
2091 VmPtr->Ip += (UINTN) Addr + Size;
2092 } else {
2093 VmPtr->Ip = (VMIP) Addr;
2094 }
2095 }
2096
2097 return EFI_SUCCESS;
2098 }
2099
2100
2101 /**
2102 Execute the EBC JMP8 instruction.
2103
2104 Instruction syntax:
2105 JMP8{cs|cc} Offset/2
2106
2107 @param VmPtr A pointer to a VM context.
2108
2109 @retval EFI_SUCCESS The instruction is executed successfully.
2110
2111 **/
2112 EFI_STATUS
2113 ExecuteJMP8 (
2114 IN VM_CONTEXT *VmPtr
2115 )
2116 {
2117 UINT8 Opcode;
2118 UINT8 ConditionFlag;
2119 UINT8 CompareSet;
2120 INT8 Offset;
2121
2122 //
2123 // Decode instruction.
2124 //
2125 Opcode = GETOPCODE (VmPtr);
2126 CompareSet = (UINT8) (((Opcode & JMP_M_CS) != 0) ? 1 : 0);
2127 ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
2128
2129 //
2130 // If we haven't met the condition, then simply advance the IP and return
2131 //
2132 if ((Opcode & CONDITION_M_CONDITIONAL) != 0) {
2133 if (CompareSet != ConditionFlag) {
2134 VmPtr->Ip += 2;
2135 return EFI_SUCCESS;
2136 }
2137 }
2138 //
2139 // Get the offset from the instruction stream. It's relative to the
2140 // following instruction, and divided by 2.
2141 //
2142 Offset = VmReadImmed8 (VmPtr, 1);
2143 //
2144 // Want to check for offset == -2 and then raise an exception?
2145 //
2146 VmPtr->Ip += (Offset * 2) + 2;
2147 return EFI_SUCCESS;
2148 }
2149
2150
2151 /**
2152 Execute the EBC MOVI.
2153
2154 Instruction syntax:
2155
2156 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2157
2158 First variable character specifies the move size
2159 Second variable character specifies size of the immediate data
2160
2161 Sign-extend the immediate data to the size of the operation, and zero-extend
2162 if storing to a register.
2163
2164 Operand1 direct with index/immed is invalid.
2165
2166 @param VmPtr A pointer to a VM context.
2167
2168 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2169 @retval EFI_SUCCESS The instruction is executed successfully.
2170
2171 **/
2172 EFI_STATUS
2173 ExecuteMOVI (
2174 IN VM_CONTEXT *VmPtr
2175 )
2176 {
2177 UINT8 Opcode;
2178 UINT8 Operands;
2179 UINT8 Size;
2180 INT16 Index16;
2181 INT64 ImmData64;
2182 UINT64 Op1;
2183 UINT64 Mask64;
2184
2185 //
2186 // Get the opcode and operands byte so we can get R1 and R2
2187 //
2188 Opcode = GETOPCODE (VmPtr);
2189 Operands = GETOPERANDS (VmPtr);
2190
2191 //
2192 // Get the index (16-bit) if present
2193 //
2194 if ((Operands & MOVI_M_IMMDATA) != 0) {
2195 Index16 = VmReadIndex16 (VmPtr, 2);
2196 Size = 4;
2197 } else {
2198 Index16 = 0;
2199 Size = 2;
2200 }
2201 //
2202 // Extract the immediate data. Sign-extend always.
2203 //
2204 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
2205 ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);
2206 Size += 2;
2207 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
2208 ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);
2209 Size += 4;
2210 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
2211 ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);
2212 Size += 8;
2213 } else {
2214 //
2215 // Invalid encoding
2216 //
2217 EbcDebugSignalException (
2218 EXCEPT_EBC_INSTRUCTION_ENCODING,
2219 EXCEPTION_FLAG_FATAL,
2220 VmPtr
2221 );
2222 return EFI_UNSUPPORTED;
2223 }
2224 //
2225 // Now write back the result
2226 //
2227 if (!OPERAND1_INDIRECT (Operands)) {
2228 //
2229 // Operand1 direct. Make sure it didn't have an index.
2230 //
2231 if ((Operands & MOVI_M_IMMDATA) != 0) {
2232 EbcDebugSignalException (
2233 EXCEPT_EBC_INSTRUCTION_ENCODING,
2234 EXCEPTION_FLAG_FATAL,
2235 VmPtr
2236 );
2237 return EFI_UNSUPPORTED;
2238 }
2239 //
2240 // Writing directly to a register. Clear unused bits.
2241 //
2242 if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
2243 Mask64 = 0x000000FF;
2244 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
2245 Mask64 = 0x0000FFFF;
2246 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
2247 Mask64 = 0x00000000FFFFFFFF;
2248 } else {
2249 Mask64 = (UINT64)~0;
2250 }
2251
2252 VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;
2253 } else {
2254 //
2255 // Get the address then write back based on size of the move
2256 //
2257 Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
2258 if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
2259 VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);
2260 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
2261 VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);
2262 } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
2263 VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);
2264 } else {
2265 VmWriteMem64 (VmPtr, (UINTN) Op1, ImmData64);
2266 }
2267 }
2268 //
2269 // Advance the instruction pointer
2270 //
2271 VmPtr->Ip += Size;
2272 return EFI_SUCCESS;
2273 }
2274
2275
2276 /**
2277 Execute the EBC MOV immediate natural. This instruction moves an immediate
2278 index value into a register or memory location.
2279
2280 Instruction syntax:
2281
2282 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2283
2284 @param VmPtr A pointer to a VM context.
2285
2286 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2287 @retval EFI_SUCCESS The instruction is executed successfully.
2288
2289 **/
2290 EFI_STATUS
2291 ExecuteMOVIn (
2292 IN VM_CONTEXT *VmPtr
2293 )
2294 {
2295 UINT8 Opcode;
2296 UINT8 Operands;
2297 UINT8 Size;
2298 INT16 Index16;
2299 INT16 ImmedIndex16;
2300 INT32 ImmedIndex32;
2301 INT64 ImmedIndex64;
2302 UINT64 Op1;
2303
2304 //
2305 // Get the opcode and operands byte so we can get R1 and R2
2306 //
2307 Opcode = GETOPCODE (VmPtr);
2308 Operands = GETOPERANDS (VmPtr);
2309
2310 //
2311 // Get the operand1 index (16-bit) if present
2312 //
2313 if ((Operands & MOVI_M_IMMDATA) != 0) {
2314 Index16 = VmReadIndex16 (VmPtr, 2);
2315 Size = 4;
2316 } else {
2317 Index16 = 0;
2318 Size = 2;
2319 }
2320 //
2321 // Extract the immediate data and convert to a 64-bit index.
2322 //
2323 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
2324 ImmedIndex16 = VmReadIndex16 (VmPtr, Size);
2325 ImmedIndex64 = (INT64) ImmedIndex16;
2326 Size += 2;
2327 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
2328 ImmedIndex32 = VmReadIndex32 (VmPtr, Size);
2329 ImmedIndex64 = (INT64) ImmedIndex32;
2330 Size += 4;
2331 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
2332 ImmedIndex64 = VmReadIndex64 (VmPtr, Size);
2333 Size += 8;
2334 } else {
2335 //
2336 // Invalid encoding
2337 //
2338 EbcDebugSignalException (
2339 EXCEPT_EBC_INSTRUCTION_ENCODING,
2340 EXCEPTION_FLAG_FATAL,
2341 VmPtr
2342 );
2343 return EFI_UNSUPPORTED;
2344 }
2345 //
2346 // Now write back the result
2347 //
2348 if (!OPERAND1_INDIRECT (Operands)) {
2349 //
2350 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2351 // is illegal
2352 //
2353 if ((Operands & MOVI_M_IMMDATA) != 0) {
2354 EbcDebugSignalException (
2355 EXCEPT_EBC_INSTRUCTION_ENCODING,
2356 EXCEPTION_FLAG_FATAL,
2357 VmPtr
2358 );
2359 return EFI_UNSUPPORTED;
2360 }
2361
2362 VmPtr->R[OPERAND1_REGNUM (Operands)] = ImmedIndex64;
2363 } else {
2364 //
2365 // Get the address
2366 //
2367 Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
2368 VmWriteMemN (VmPtr, (UINTN) Op1, (INTN) ImmedIndex64);
2369 }
2370 //
2371 // Advance the instruction pointer
2372 //
2373 VmPtr->Ip += Size;
2374 return EFI_SUCCESS;
2375 }
2376
2377
2378 /**
2379 Execute the EBC MOVREL instruction.
2380 Dest <- Ip + ImmData
2381
2382 Instruction syntax:
2383
2384 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2385
2386 @param VmPtr A pointer to a VM context.
2387
2388 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2389 @retval EFI_SUCCESS The instruction is executed successfully.
2390
2391 **/
2392 EFI_STATUS
2393 ExecuteMOVREL (
2394 IN VM_CONTEXT *VmPtr
2395 )
2396 {
2397 UINT8 Opcode;
2398 UINT8 Operands;
2399 UINT8 Size;
2400 INT16 Index16;
2401 INT64 ImmData64;
2402 UINT64 Op1;
2403 UINT64 Op2;
2404
2405 //
2406 // Get the opcode and operands byte so we can get R1 and R2
2407 //
2408 Opcode = GETOPCODE (VmPtr);
2409 Operands = GETOPERANDS (VmPtr);
2410
2411 //
2412 // Get the Operand 1 index (16-bit) if present
2413 //
2414 if ((Operands & MOVI_M_IMMDATA) != 0) {
2415 Index16 = VmReadIndex16 (VmPtr, 2);
2416 Size = 4;
2417 } else {
2418 Index16 = 0;
2419 Size = 2;
2420 }
2421 //
2422 // Get the immediate data.
2423 //
2424 if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
2425 ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);
2426 Size += 2;
2427 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
2428 ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);
2429 Size += 4;
2430 } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
2431 ImmData64 = VmReadImmed64 (VmPtr, Size);
2432 Size += 8;
2433 } else {
2434 //
2435 // Invalid encoding
2436 //
2437 EbcDebugSignalException (
2438 EXCEPT_EBC_INSTRUCTION_ENCODING,
2439 EXCEPTION_FLAG_FATAL,
2440 VmPtr
2441 );
2442 return EFI_UNSUPPORTED;
2443 }
2444 //
2445 // Compute the value and write back the result
2446 //
2447 Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);
2448 if (!OPERAND1_INDIRECT (Operands)) {
2449 //
2450 // Check for illegal combination of operand1 direct with immediate data
2451 //
2452 if ((Operands & MOVI_M_IMMDATA) != 0) {
2453 EbcDebugSignalException (
2454 EXCEPT_EBC_INSTRUCTION_ENCODING,
2455 EXCEPTION_FLAG_FATAL,
2456 VmPtr
2457 );
2458 return EFI_UNSUPPORTED;
2459 }
2460
2461 VmPtr->R[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;
2462 } else {
2463 //
2464 // Get the address = [Rx] + Index16
2465 // Write back the result. Always a natural size write, since
2466 // we're talking addresses here.
2467 //
2468 Op1 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
2469 VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);
2470 }
2471 //
2472 // Advance the instruction pointer
2473 //
2474 VmPtr->Ip += Size;
2475 return EFI_SUCCESS;
2476 }
2477
2478
2479 /**
2480 Execute the EBC MOVsnw instruction. This instruction loads a signed
2481 natural value from memory or register to another memory or register. On
2482 32-bit machines, the value gets sign-extended to 64 bits if the destination
2483 is a register.
2484
2485 Instruction syntax:
2486
2487 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2488
2489 0:7 1=>operand1 index present
2490 0:6 1=>operand2 index present
2491
2492 @param VmPtr A pointer to a VM context.
2493
2494 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2495 @retval EFI_SUCCESS The instruction is executed successfully.
2496
2497 **/
2498 EFI_STATUS
2499 ExecuteMOVsnw (
2500 IN VM_CONTEXT *VmPtr
2501 )
2502 {
2503 UINT8 Opcode;
2504 UINT8 Operands;
2505 UINT8 Size;
2506 INT16 Op1Index;
2507 INT16 Op2Index;
2508 UINT64 Op2;
2509
2510 //
2511 // Get the opcode and operand bytes
2512 //
2513 Opcode = GETOPCODE (VmPtr);
2514 Operands = GETOPERANDS (VmPtr);
2515
2516 Op1Index = Op2Index = 0;
2517
2518 //
2519 // Get the indexes if present.
2520 //
2521 Size = 2;
2522 if ((Opcode & OPCODE_M_IMMED_OP1) !=0) {
2523 if (OPERAND1_INDIRECT (Operands)) {
2524 Op1Index = VmReadIndex16 (VmPtr, 2);
2525 } else {
2526 //
2527 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2528 //
2529 EbcDebugSignalException (
2530 EXCEPT_EBC_INSTRUCTION_ENCODING,
2531 EXCEPTION_FLAG_FATAL,
2532 VmPtr
2533 );
2534 return EFI_UNSUPPORTED;
2535 }
2536
2537 Size += sizeof (UINT16);
2538 }
2539
2540 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
2541 if (OPERAND2_INDIRECT (Operands)) {
2542 Op2Index = VmReadIndex16 (VmPtr, Size);
2543 } else {
2544 Op2Index = VmReadImmed16 (VmPtr, Size);
2545 }
2546
2547 Size += sizeof (UINT16);
2548 }
2549 //
2550 // Get the data from the source.
2551 //
2552 Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));
2553 if (OPERAND2_INDIRECT (Operands)) {
2554 Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);
2555 }
2556 //
2557 // Now write back the result.
2558 //
2559 if (!OPERAND1_INDIRECT (Operands)) {
2560 VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;
2561 } else {
2562 VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
2563 }
2564 //
2565 // Advance the instruction pointer
2566 //
2567 VmPtr->Ip += Size;
2568 return EFI_SUCCESS;
2569 }
2570
2571
2572 /**
2573 Execute the EBC MOVsnw instruction. This instruction loads a signed
2574 natural value from memory or register to another memory or register. On
2575 32-bit machines, the value gets sign-extended to 64 bits if the destination
2576 is a register.
2577
2578 Instruction syntax:
2579
2580 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2581
2582 0:7 1=>operand1 index present
2583 0:6 1=>operand2 index present
2584
2585 @param VmPtr A pointer to a VM context.
2586
2587 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2588 @retval EFI_SUCCESS The instruction is executed successfully.
2589
2590 **/
2591 EFI_STATUS
2592 ExecuteMOVsnd (
2593 IN VM_CONTEXT *VmPtr
2594 )
2595 {
2596 UINT8 Opcode;
2597 UINT8 Operands;
2598 UINT8 Size;
2599 INT32 Op1Index;
2600 INT32 Op2Index;
2601 UINT64 Op2;
2602
2603 //
2604 // Get the opcode and operand bytes
2605 //
2606 Opcode = GETOPCODE (VmPtr);
2607 Operands = GETOPERANDS (VmPtr);
2608
2609 Op1Index = Op2Index = 0;
2610
2611 //
2612 // Get the indexes if present.
2613 //
2614 Size = 2;
2615 if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
2616 if (OPERAND1_INDIRECT (Operands)) {
2617 Op1Index = VmReadIndex32 (VmPtr, 2);
2618 } else {
2619 //
2620 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2621 //
2622 EbcDebugSignalException (
2623 EXCEPT_EBC_INSTRUCTION_ENCODING,
2624 EXCEPTION_FLAG_FATAL,
2625 VmPtr
2626 );
2627 return EFI_UNSUPPORTED;
2628 }
2629
2630 Size += sizeof (UINT32);
2631 }
2632
2633 if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
2634 if (OPERAND2_INDIRECT (Operands)) {
2635 Op2Index = VmReadIndex32 (VmPtr, Size);
2636 } else {
2637 Op2Index = VmReadImmed32 (VmPtr, Size);
2638 }
2639
2640 Size += sizeof (UINT32);
2641 }
2642 //
2643 // Get the data from the source.
2644 //
2645 Op2 = (INT64) ((INTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Op2Index));
2646 if (OPERAND2_INDIRECT (Operands)) {
2647 Op2 = (INT64) (INTN) VmReadMemN (VmPtr, (UINTN) Op2);
2648 }
2649 //
2650 // Now write back the result.
2651 //
2652 if (!OPERAND1_INDIRECT (Operands)) {
2653 VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;
2654 } else {
2655 VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
2656 }
2657 //
2658 // Advance the instruction pointer
2659 //
2660 VmPtr->Ip += Size;
2661 return EFI_SUCCESS;
2662 }
2663
2664
2665 /**
2666 Execute the EBC PUSHn instruction
2667
2668 Instruction syntax:
2669 PUSHn {@}R1 {Index16|Immed16}
2670
2671 @param VmPtr A pointer to a VM context.
2672
2673 @retval EFI_SUCCESS The instruction is executed successfully.
2674
2675 **/
2676 EFI_STATUS
2677 ExecutePUSHn (
2678 IN VM_CONTEXT *VmPtr
2679 )
2680 {
2681 UINT8 Opcode;
2682 UINT8 Operands;
2683 INT16 Index16;
2684 UINTN DataN;
2685
2686 //
2687 // Get opcode and operands
2688 //
2689 Opcode = GETOPCODE (VmPtr);
2690 Operands = GETOPERANDS (VmPtr);
2691
2692 //
2693 // Get index if present
2694 //
2695 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
2696 if (OPERAND1_INDIRECT (Operands)) {
2697 Index16 = VmReadIndex16 (VmPtr, 2);
2698 } else {
2699 Index16 = VmReadImmed16 (VmPtr, 2);
2700 }
2701
2702 VmPtr->Ip += 4;
2703 } else {
2704 Index16 = 0;
2705 VmPtr->Ip += 2;
2706 }
2707 //
2708 // Get the data to push
2709 //
2710 if (OPERAND1_INDIRECT (Operands)) {
2711 DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
2712 } else {
2713 DataN = (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16);
2714 }
2715 //
2716 // Adjust the stack down.
2717 //
2718 VmPtr->R[0] -= sizeof (UINTN);
2719 VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], DataN);
2720 return EFI_SUCCESS;
2721 }
2722
2723
2724 /**
2725 Execute the EBC PUSH instruction.
2726
2727 Instruction syntax:
2728 PUSH[32|64] {@}R1 {Index16|Immed16}
2729
2730 @param VmPtr A pointer to a VM context.
2731
2732 @retval EFI_SUCCESS The instruction is executed successfully.
2733
2734 **/
2735 EFI_STATUS
2736 ExecutePUSH (
2737 IN VM_CONTEXT *VmPtr
2738 )
2739 {
2740 UINT8 Opcode;
2741 UINT8 Operands;
2742 UINT32 Data32;
2743 UINT64 Data64;
2744 INT16 Index16;
2745
2746 //
2747 // Get opcode and operands
2748 //
2749 Opcode = GETOPCODE (VmPtr);
2750 Operands = GETOPERANDS (VmPtr);
2751 //
2752 // Get immediate index if present, then advance the IP.
2753 //
2754 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
2755 if (OPERAND1_INDIRECT (Operands)) {
2756 Index16 = VmReadIndex16 (VmPtr, 2);
2757 } else {
2758 Index16 = VmReadImmed16 (VmPtr, 2);
2759 }
2760
2761 VmPtr->Ip += 4;
2762 } else {
2763 Index16 = 0;
2764 VmPtr->Ip += 2;
2765 }
2766 //
2767 // Get the data to push
2768 //
2769 if ((Opcode & PUSHPOP_M_64) != 0) {
2770 if (OPERAND1_INDIRECT (Operands)) {
2771 Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
2772 } else {
2773 Data64 = (UINT64) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
2774 }
2775 //
2776 // Adjust the stack down, then write back the data
2777 //
2778 VmPtr->R[0] -= sizeof (UINT64);
2779 VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], Data64);
2780 } else {
2781 //
2782 // 32-bit data
2783 //
2784 if (OPERAND1_INDIRECT (Operands)) {
2785 Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16));
2786 } else {
2787 Data32 = (UINT32) VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16;
2788 }
2789 //
2790 // Adjust the stack down and write the data
2791 //
2792 VmPtr->R[0] -= sizeof (UINT32);
2793 VmWriteMem32 (VmPtr, (UINTN) VmPtr->R[0], Data32);
2794 }
2795
2796 return EFI_SUCCESS;
2797 }
2798
2799
2800 /**
2801 Execute the EBC POPn instruction.
2802
2803 Instruction syntax:
2804 POPn {@}R1 {Index16|Immed16}
2805
2806 @param VmPtr A pointer to a VM context.
2807
2808 @retval EFI_SUCCESS The instruction is executed successfully.
2809
2810 **/
2811 EFI_STATUS
2812 ExecutePOPn (
2813 IN VM_CONTEXT *VmPtr
2814 )
2815 {
2816 UINT8 Opcode;
2817 UINT8 Operands;
2818 INT16 Index16;
2819 UINTN DataN;
2820
2821 //
2822 // Get opcode and operands
2823 //
2824 Opcode = GETOPCODE (VmPtr);
2825 Operands = GETOPERANDS (VmPtr);
2826 //
2827 // Get immediate data if present, and advance the IP
2828 //
2829 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
2830 if (OPERAND1_INDIRECT (Operands)) {
2831 Index16 = VmReadIndex16 (VmPtr, 2);
2832 } else {
2833 Index16 = VmReadImmed16 (VmPtr, 2);
2834 }
2835
2836 VmPtr->Ip += 4;
2837 } else {
2838 Index16 = 0;
2839 VmPtr->Ip += 2;
2840 }
2841 //
2842 // Read the data off the stack, then adjust the stack pointer
2843 //
2844 DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);
2845 VmPtr->R[0] += sizeof (UINTN);
2846 //
2847 // Do the write-back
2848 //
2849 if (OPERAND1_INDIRECT (Operands)) {
2850 VmWriteMemN (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), DataN);
2851 } else {
2852 VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16);
2853 }
2854
2855 return EFI_SUCCESS;
2856 }
2857
2858
2859 /**
2860 Execute the EBC POP instruction.
2861
2862 Instruction syntax:
2863 POPn {@}R1 {Index16|Immed16}
2864
2865 @param VmPtr A pointer to a VM context.
2866
2867 @retval EFI_SUCCESS The instruction is executed successfully.
2868
2869 **/
2870 EFI_STATUS
2871 ExecutePOP (
2872 IN VM_CONTEXT *VmPtr
2873 )
2874 {
2875 UINT8 Opcode;
2876 UINT8 Operands;
2877 INT16 Index16;
2878 INT32 Data32;
2879 UINT64 Data64;
2880
2881 //
2882 // Get opcode and operands
2883 //
2884 Opcode = GETOPCODE (VmPtr);
2885 Operands = GETOPERANDS (VmPtr);
2886 //
2887 // Get immediate data if present, and advance the IP.
2888 //
2889 if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
2890 if (OPERAND1_INDIRECT (Operands)) {
2891 Index16 = VmReadIndex16 (VmPtr, 2);
2892 } else {
2893 Index16 = VmReadImmed16 (VmPtr, 2);
2894 }
2895
2896 VmPtr->Ip += 4;
2897 } else {
2898 Index16 = 0;
2899 VmPtr->Ip += 2;
2900 }
2901 //
2902 // Get the data off the stack, then write it to the appropriate location
2903 //
2904 if ((Opcode & PUSHPOP_M_64) != 0) {
2905 //
2906 // Read the data off the stack, then adjust the stack pointer
2907 //
2908 Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);
2909 VmPtr->R[0] += sizeof (UINT64);
2910 //
2911 // Do the write-back
2912 //
2913 if (OPERAND1_INDIRECT (Operands)) {
2914 VmWriteMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data64);
2915 } else {
2916 VmPtr->R[OPERAND1_REGNUM (Operands)] = Data64 + Index16;
2917 }
2918 } else {
2919 //
2920 // 32-bit pop. Read it off the stack and adjust the stack pointer
2921 //
2922 Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->R[0]);
2923 VmPtr->R[0] += sizeof (UINT32);
2924 //
2925 // Do the write-back
2926 //
2927 if (OPERAND1_INDIRECT (Operands)) {
2928 VmWriteMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND1_REGNUM (Operands)] + Index16), Data32);
2929 } else {
2930 VmPtr->R[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;
2931 }
2932 }
2933
2934 return EFI_SUCCESS;
2935 }
2936
2937
2938 /**
2939 Implements the EBC CALL instruction.
2940
2941 Instruction format:
2942 CALL64 Immed64
2943 CALL32 {@}R1 {Immed32|Index32}
2944 CALLEX64 Immed64
2945 CALLEX16 {@}R1 {Immed32}
2946
2947 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2948
2949 @param VmPtr A pointer to a VM context.
2950
2951 @retval EFI_SUCCESS The instruction is executed successfully.
2952
2953 **/
2954 EFI_STATUS
2955 ExecuteCALL (
2956 IN VM_CONTEXT *VmPtr
2957 )
2958 {
2959 UINT8 Opcode;
2960 UINT8 Operands;
2961 INT32 Immed32;
2962 UINT8 Size;
2963 INT64 Immed64;
2964 VOID *FramePtr;
2965
2966 //
2967 // Get opcode and operands
2968 //
2969 Opcode = GETOPCODE (VmPtr);
2970 Operands = GETOPERANDS (VmPtr);
2971 //
2972 // Assign these as well to avoid compiler warnings
2973 //
2974 Immed64 = 0;
2975 Immed32 = 0;
2976
2977 FramePtr = VmPtr->FramePtr;
2978 //
2979 // Determine the instruction size, and get immediate data if present
2980 //
2981 if ((Opcode & OPCODE_M_IMMDATA) != 0) {
2982 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
2983 Immed64 = VmReadImmed64 (VmPtr, 2);
2984 Size = 10;
2985 } else {
2986 //
2987 // If register operand is indirect, then the immediate data is an index
2988 //
2989 if (OPERAND1_INDIRECT (Operands)) {
2990 Immed32 = VmReadIndex32 (VmPtr, 2);
2991 } else {
2992 Immed32 = VmReadImmed32 (VmPtr, 2);
2993 }
2994
2995 Size = 6;
2996 }
2997 } else {
2998 Size = 2;
2999 }
3000 //
3001 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3002 // put our return address and frame pointer on the VM stack.
3003 //
3004 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
3005 VmPtr->R[0] -= 8;
3006 VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
3007 VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
3008 VmPtr->R[0] -= 8;
3009 VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
3010 }
3011 //
3012 // If 64-bit data, then absolute jump only
3013 //
3014 if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
3015 //
3016 // Native or EBC call?
3017 //
3018 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
3019 VmPtr->Ip = (VMIP) (UINTN) Immed64;
3020 } else {
3021 //
3022 // Call external function, get the return value, and advance the IP
3023 //
3024 EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);
3025 }
3026 } else {
3027 //
3028 // Get the register data. If operand1 == 0, then ignore register and
3029 // take immediate data as relative or absolute address.
3030 // Compiler should take care of upper bits if 32-bit machine.
3031 //
3032 if (OPERAND1_REGNUM (Operands) != 0) {
3033 Immed64 = (UINT64) (UINTN) VmPtr->R[OPERAND1_REGNUM (Operands)];
3034 }
3035 //
3036 // Get final address
3037 //
3038 if (OPERAND1_INDIRECT (Operands)) {
3039 Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));
3040 } else {
3041 Immed64 += Immed32;
3042 }
3043 //
3044 // Now determine if external call, and then if relative or absolute
3045 //
3046 if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
3047 //
3048 // EBC call. Relative or absolute? If relative, then it's relative to the
3049 // start of the next instruction.
3050 //
3051 if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
3052 VmPtr->Ip += Immed64 + Size;
3053 } else {
3054 VmPtr->Ip = (VMIP) (UINTN) Immed64;
3055 }
3056 } else {
3057 //
3058 // Native call. Relative or absolute?
3059 //
3060 if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
3061 EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->R[0], FramePtr, Size);
3062 } else {
3063 if ((VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) != 0) {
3064 CpuBreakpoint ();
3065 }
3066
3067 EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->R[0], FramePtr, Size);
3068 }
3069 }
3070 }
3071
3072 return EFI_SUCCESS;
3073 }
3074
3075
3076 /**
3077 Execute the EBC RET instruction.
3078
3079 Instruction syntax:
3080 RET
3081
3082 @param VmPtr A pointer to a VM context.
3083
3084 @retval EFI_SUCCESS The instruction is executed successfully.
3085
3086 **/
3087 EFI_STATUS
3088 ExecuteRET (
3089 IN VM_CONTEXT *VmPtr
3090 )
3091 {
3092 //
3093 // If we're at the top of the stack, then simply set the done
3094 // flag and return
3095 //
3096 if (VmPtr->StackRetAddr == (UINT64) VmPtr->R[0]) {
3097 VmPtr->StopFlags |= STOPFLAG_APP_DONE;
3098 } else {
3099 //
3100 // Pull the return address off the VM app's stack and set the IP
3101 // to it
3102 //
3103 if (!IS_ALIGNED ((UINTN) VmPtr->R[0], sizeof (UINT16))) {
3104 EbcDebugSignalException (
3105 EXCEPT_EBC_ALIGNMENT_CHECK,
3106 EXCEPTION_FLAG_FATAL,
3107 VmPtr
3108 );
3109 }
3110 //
3111 // Restore the IP and frame pointer from the stack
3112 //
3113 VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->R[0]);
3114 VmPtr->R[0] += 8;
3115 VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->R[0]);
3116 VmPtr->R[0] += 8;
3117 }
3118
3119 return EFI_SUCCESS;
3120 }
3121
3122
3123 /**
3124 Execute the EBC CMP instruction.
3125
3126 Instruction syntax:
3127 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3128
3129 @param VmPtr A pointer to a VM context.
3130
3131 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3132 @retval EFI_SUCCESS The instruction is executed successfully.
3133
3134 **/
3135 EFI_STATUS
3136 ExecuteCMP (
3137 IN VM_CONTEXT *VmPtr
3138 )
3139 {
3140 UINT8 Opcode;
3141 UINT8 Operands;
3142 UINT8 Size;
3143 INT16 Index16;
3144 UINT32 Flag;
3145 INT64 Op2;
3146 INT64 Op1;
3147
3148 //
3149 // Get opcode and operands
3150 //
3151 Opcode = GETOPCODE (VmPtr);
3152 Operands = GETOPERANDS (VmPtr);
3153 //
3154 // Get the register data we're going to compare to
3155 //
3156 Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];
3157 //
3158 // Get immediate data
3159 //
3160 if ((Opcode & OPCODE_M_IMMDATA) != 0) {
3161 if (OPERAND2_INDIRECT (Operands)) {
3162 Index16 = VmReadIndex16 (VmPtr, 2);
3163 } else {
3164 Index16 = VmReadImmed16 (VmPtr, 2);
3165 }
3166
3167 Size = 4;
3168 } else {
3169 Index16 = 0;
3170 Size = 2;
3171 }
3172 //
3173 // Now get Op2
3174 //
3175 if (OPERAND2_INDIRECT (Operands)) {
3176 if ((Opcode & OPCODE_M_64BIT) != 0) {
3177 Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16));
3178 } else {
3179 //
3180 // 32-bit operations. 0-extend the values for all cases.
3181 //
3182 Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16)));
3183 }
3184 } else {
3185 Op2 = VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16;
3186 }
3187 //
3188 // Now do the compare
3189 //
3190 Flag = 0;
3191 if ((Opcode & OPCODE_M_64BIT) != 0) {
3192 //
3193 // 64-bit compares
3194 //
3195 switch (Opcode & OPCODE_M_OPCODE) {
3196 case OPCODE_CMPEQ:
3197 if (Op1 == Op2) {
3198 Flag = 1;
3199 }
3200 break;
3201
3202 case OPCODE_CMPLTE:
3203 if (Op1 <= Op2) {
3204 Flag = 1;
3205 }
3206 break;
3207
3208 case OPCODE_CMPGTE:
3209 if (Op1 >= Op2) {
3210 Flag = 1;
3211 }
3212 break;
3213
3214 case OPCODE_CMPULTE:
3215 if ((UINT64) Op1 <= (UINT64) Op2) {
3216 Flag = 1;
3217 }
3218 break;
3219
3220 case OPCODE_CMPUGTE:
3221 if ((UINT64) Op1 >= (UINT64) Op2) {
3222 Flag = 1;
3223 }
3224 break;
3225
3226 default:
3227 ASSERT (0);
3228 }
3229 } else {
3230 //
3231 // 32-bit compares
3232 //
3233 switch (Opcode & OPCODE_M_OPCODE) {
3234 case OPCODE_CMPEQ:
3235 if ((INT32) Op1 == (INT32) Op2) {
3236 Flag = 1;
3237 }
3238 break;
3239
3240 case OPCODE_CMPLTE:
3241 if ((INT32) Op1 <= (INT32) Op2) {
3242 Flag = 1;
3243 }
3244 break;
3245
3246 case OPCODE_CMPGTE:
3247 if ((INT32) Op1 >= (INT32) Op2) {
3248 Flag = 1;
3249 }
3250 break;
3251
3252 case OPCODE_CMPULTE:
3253 if ((UINT32) Op1 <= (UINT32) Op2) {
3254 Flag = 1;
3255 }
3256 break;
3257
3258 case OPCODE_CMPUGTE:
3259 if ((UINT32) Op1 >= (UINT32) Op2) {
3260 Flag = 1;
3261 }
3262 break;
3263
3264 default:
3265 ASSERT (0);
3266 }
3267 }
3268 //
3269 // Now set the flag accordingly for the comparison
3270 //
3271 if (Flag != 0) {
3272 VMFLAG_SET (VmPtr, VMFLAGS_CC);
3273 } else {
3274 VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);
3275 }
3276 //
3277 // Advance the IP
3278 //
3279 VmPtr->Ip += Size;
3280 return EFI_SUCCESS;
3281 }
3282
3283
3284 /**
3285 Execute the EBC CMPI instruction
3286
3287 Instruction syntax:
3288 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3289
3290 @param VmPtr A pointer to a VM context.
3291
3292 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3293 @retval EFI_SUCCESS The instruction is executed successfully.
3294
3295 **/
3296 EFI_STATUS
3297 ExecuteCMPI (
3298 IN VM_CONTEXT *VmPtr
3299 )
3300 {
3301 UINT8 Opcode;
3302 UINT8 Operands;
3303 UINT8 Size;
3304 INT64 Op1;
3305 INT64 Op2;
3306 INT16 Index16;
3307 UINT32 Flag;
3308
3309 //
3310 // Get opcode and operands
3311 //
3312 Opcode = GETOPCODE (VmPtr);
3313 Operands = GETOPERANDS (VmPtr);
3314
3315 //
3316 // Get operand1 index if present
3317 //
3318 Size = 2;
3319 if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
3320 Index16 = VmReadIndex16 (VmPtr, 2);
3321 Size += 2;
3322 } else {
3323 Index16 = 0;
3324 }
3325 //
3326 // Get operand1 data we're going to compare to
3327 //
3328 Op1 = (INT64) VmPtr->R[OPERAND1_REGNUM (Operands)];
3329 if (OPERAND1_INDIRECT (Operands)) {
3330 //
3331 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3332 //
3333 if ((Opcode & OPCODE_M_CMPI64) != 0) {
3334 Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);
3335 } else {
3336 Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);
3337 }
3338 } else {
3339 //
3340 // Better not have been an index with direct. That is, CMPI R1 Index,...
3341 // is illegal.
3342 //
3343 if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
3344 EbcDebugSignalException (
3345 EXCEPT_EBC_INSTRUCTION_ENCODING,
3346 EXCEPTION_FLAG_ERROR,
3347 VmPtr
3348 );
3349 VmPtr->Ip += Size;
3350 return EFI_UNSUPPORTED;
3351 }
3352 }
3353 //
3354 // Get immediate data -- 16- or 32-bit sign extended
3355 //
3356 if ((Opcode & OPCODE_M_CMPI32_DATA) != 0) {
3357 Op2 = (INT64) VmReadImmed32 (VmPtr, Size);
3358 Size += 4;
3359 } else {
3360 //
3361 // 16-bit immediate data. Sign extend always.
3362 //
3363 Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));
3364 Size += 2;
3365 }
3366 //
3367 // Now do the compare
3368 //
3369 Flag = 0;
3370 if ((Opcode & OPCODE_M_CMPI64) != 0) {
3371 //
3372 // 64 bit comparison
3373 //
3374 switch (Opcode & OPCODE_M_OPCODE) {
3375 case OPCODE_CMPIEQ:
3376 if (Op1 == (INT64) Op2) {
3377 Flag = 1;
3378 }
3379 break;
3380
3381 case OPCODE_CMPILTE:
3382 if (Op1 <= (INT64) Op2) {
3383 Flag = 1;
3384 }
3385 break;
3386
3387 case OPCODE_CMPIGTE:
3388 if (Op1 >= (INT64) Op2) {
3389 Flag = 1;
3390 }
3391 break;
3392
3393 case OPCODE_CMPIULTE:
3394 if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {
3395 Flag = 1;
3396 }
3397 break;
3398
3399 case OPCODE_CMPIUGTE:
3400 if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {
3401 Flag = 1;
3402 }
3403 break;
3404
3405 default:
3406 ASSERT (0);
3407 }
3408 } else {
3409 //
3410 // 32-bit comparisons
3411 //
3412 switch (Opcode & OPCODE_M_OPCODE) {
3413 case OPCODE_CMPIEQ:
3414 if ((INT32) Op1 == Op2) {
3415 Flag = 1;
3416 }
3417 break;
3418
3419 case OPCODE_CMPILTE:
3420 if ((INT32) Op1 <= Op2) {
3421 Flag = 1;
3422 }
3423 break;
3424
3425 case OPCODE_CMPIGTE:
3426 if ((INT32) Op1 >= Op2) {
3427 Flag = 1;
3428 }
3429 break;
3430
3431 case OPCODE_CMPIULTE:
3432 if ((UINT32) Op1 <= (UINT32) Op2) {
3433 Flag = 1;
3434 }
3435 break;
3436
3437 case OPCODE_CMPIUGTE:
3438 if ((UINT32) Op1 >= (UINT32) Op2) {
3439 Flag = 1;
3440 }
3441 break;
3442
3443 default:
3444 ASSERT (0);
3445 }
3446 }
3447 //
3448 // Now set the flag accordingly for the comparison
3449 //
3450 if (Flag != 0) {
3451 VMFLAG_SET (VmPtr, VMFLAGS_CC);
3452 } else {
3453 VMFLAG_CLEAR (VmPtr, VMFLAGS_CC);
3454 }
3455 //
3456 // Advance the IP
3457 //
3458 VmPtr->Ip += Size;
3459 return EFI_SUCCESS;
3460 }
3461
3462
3463 /**
3464 Execute the EBC NOT instruction.s
3465
3466 Instruction syntax:
3467 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3468
3469 @param VmPtr A pointer to a VM context.
3470 @param Op1 Operand 1 from the instruction
3471 @param Op2 Operand 2 from the instruction
3472
3473 @return ~Op2
3474
3475 **/
3476 UINT64
3477 ExecuteNOT (
3478 IN VM_CONTEXT *VmPtr,
3479 IN UINT64 Op1,
3480 IN UINT64 Op2
3481 )
3482 {
3483 return ~Op2;
3484 }
3485
3486
3487 /**
3488 Execute the EBC NEG instruction.
3489
3490 Instruction syntax:
3491 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3492
3493 @param VmPtr A pointer to a VM context.
3494 @param Op1 Operand 1 from the instruction
3495 @param Op2 Operand 2 from the instruction
3496
3497 @return Op2 * -1
3498
3499 **/
3500 UINT64
3501 ExecuteNEG (
3502 IN VM_CONTEXT *VmPtr,
3503 IN UINT64 Op1,
3504 IN UINT64 Op2
3505 )
3506 {
3507 return ~Op2 + 1;
3508 }
3509
3510
3511 /**
3512 Execute the EBC ADD instruction.
3513
3514 Instruction syntax:
3515 ADD[32|64] {@}R1, {@}R2 {Index16}
3516
3517 @param VmPtr A pointer to a VM context.
3518 @param Op1 Operand 1 from the instruction
3519 @param Op2 Operand 2 from the instruction
3520
3521 @return Op1 + Op2
3522
3523 **/
3524 UINT64
3525 ExecuteADD (
3526 IN VM_CONTEXT *VmPtr,
3527 IN UINT64 Op1,
3528 IN UINT64 Op2
3529 )
3530 {
3531 return Op1 + Op2;
3532 }
3533
3534
3535 /**
3536 Execute the EBC SUB instruction.
3537
3538 Instruction syntax:
3539 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3540
3541 @param VmPtr A pointer to a VM context.
3542 @param Op1 Operand 1 from the instruction
3543 @param Op2 Operand 2 from the instruction
3544
3545 @return Op1 - Op2
3546
3547 **/
3548 UINT64
3549 ExecuteSUB (
3550 IN VM_CONTEXT *VmPtr,
3551 IN UINT64 Op1,
3552 IN UINT64 Op2
3553 )
3554 {
3555 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3556 return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));
3557 } else {
3558 return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2));
3559 }
3560 }
3561
3562
3563 /**
3564 Execute the EBC MUL instruction.
3565
3566 Instruction syntax:
3567 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3568
3569 @param VmPtr A pointer to a VM context.
3570 @param Op1 Operand 1 from the instruction
3571 @param Op2 Operand 2 from the instruction
3572
3573 @return Op1 * Op2
3574
3575 **/
3576 UINT64
3577 ExecuteMUL (
3578 IN VM_CONTEXT *VmPtr,
3579 IN UINT64 Op1,
3580 IN UINT64 Op2
3581 )
3582 {
3583 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3584 return MultS64x64 ((INT64)Op1, (INT64)Op2);
3585 } else {
3586 return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2));
3587 }
3588 }
3589
3590
3591 /**
3592 Execute the EBC MULU instruction
3593
3594 Instruction syntax:
3595 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3596
3597 @param VmPtr A pointer to a VM context.
3598 @param Op1 Operand 1 from the instruction
3599 @param Op2 Operand 2 from the instruction
3600
3601 @return (unsigned)Op1 * (unsigned)Op2
3602
3603 **/
3604 UINT64
3605 ExecuteMULU (
3606 IN VM_CONTEXT *VmPtr,
3607 IN UINT64 Op1,
3608 IN UINT64 Op2
3609 )
3610 {
3611 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3612 return MultU64x64 (Op1, Op2);
3613 } else {
3614 return (UINT64) ((UINT32) Op1 * (UINT32) Op2);
3615 }
3616 }
3617
3618
3619 /**
3620 Execute the EBC DIV instruction.
3621
3622 Instruction syntax:
3623 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3624
3625 @param VmPtr A pointer to a VM context.
3626 @param Op1 Operand 1 from the instruction
3627 @param Op2 Operand 2 from the instruction
3628
3629 @return Op1 / Op2
3630
3631 **/
3632 UINT64
3633 ExecuteDIV (
3634 IN VM_CONTEXT *VmPtr,
3635 IN UINT64 Op1,
3636 IN UINT64 Op2
3637 )
3638 {
3639 INT64 Remainder;
3640
3641 //
3642 // Check for divide-by-0
3643 //
3644 if (Op2 == 0) {
3645 EbcDebugSignalException (
3646 EXCEPT_EBC_DIVIDE_ERROR,
3647 EXCEPTION_FLAG_FATAL,
3648 VmPtr
3649 );
3650
3651 return 0;
3652 } else {
3653 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3654 return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));
3655 } else {
3656 return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));
3657 }
3658 }
3659 }
3660
3661
3662 /**
3663 Execute the EBC DIVU instruction
3664
3665 Instruction syntax:
3666 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3667
3668 @param VmPtr A pointer to a VM context.
3669 @param Op1 Operand 1 from the instruction
3670 @param Op2 Operand 2 from the instruction
3671
3672 @return (unsigned)Op1 / (unsigned)Op2
3673
3674 **/
3675 UINT64
3676 ExecuteDIVU (
3677 IN VM_CONTEXT *VmPtr,
3678 IN UINT64 Op1,
3679 IN UINT64 Op2
3680 )
3681 {
3682 UINT64 Remainder;
3683
3684 //
3685 // Check for divide-by-0
3686 //
3687 if (Op2 == 0) {
3688 EbcDebugSignalException (
3689 EXCEPT_EBC_DIVIDE_ERROR,
3690 EXCEPTION_FLAG_FATAL,
3691 VmPtr
3692 );
3693 return 0;
3694 } else {
3695 //
3696 // Get the destination register
3697 //
3698 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3699 return (UINT64) (DivU64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder));
3700 } else {
3701 return (UINT64) ((UINT32) Op1 / (UINT32) Op2);
3702 }
3703 }
3704 }
3705
3706
3707 /**
3708 Execute the EBC MOD instruction.
3709
3710 Instruction syntax:
3711 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3712
3713 @param VmPtr A pointer to a VM context.
3714 @param Op1 Operand 1 from the instruction
3715 @param Op2 Operand 2 from the instruction
3716
3717 @return Op1 MODULUS Op2
3718
3719 **/
3720 UINT64
3721 ExecuteMOD (
3722 IN VM_CONTEXT *VmPtr,
3723 IN UINT64 Op1,
3724 IN UINT64 Op2
3725 )
3726 {
3727 INT64 Remainder;
3728
3729 //
3730 // Check for divide-by-0
3731 //
3732 if (Op2 == 0) {
3733 EbcDebugSignalException (
3734 EXCEPT_EBC_DIVIDE_ERROR,
3735 EXCEPTION_FLAG_FATAL,
3736 VmPtr
3737 );
3738 return 0;
3739 } else {
3740 DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);
3741 return Remainder;
3742 }
3743 }
3744
3745
3746 /**
3747 Execute the EBC MODU instruction.
3748
3749 Instruction syntax:
3750 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3751
3752 @param VmPtr A pointer to a VM context.
3753 @param Op1 Operand 1 from the instruction
3754 @param Op2 Operand 2 from the instruction
3755
3756 @return Op1 UNSIGNED_MODULUS Op2
3757
3758 **/
3759 UINT64
3760 ExecuteMODU (
3761 IN VM_CONTEXT *VmPtr,
3762 IN UINT64 Op1,
3763 IN UINT64 Op2
3764 )
3765 {
3766 UINT64 Remainder;
3767
3768 //
3769 // Check for divide-by-0
3770 //
3771 if (Op2 == 0) {
3772 EbcDebugSignalException (
3773 EXCEPT_EBC_DIVIDE_ERROR,
3774 EXCEPTION_FLAG_FATAL,
3775 VmPtr
3776 );
3777 return 0;
3778 } else {
3779 DivU64x64Remainder (Op1, Op2, &Remainder);
3780 return Remainder;
3781 }
3782 }
3783
3784
3785 /**
3786 Execute the EBC AND instruction.
3787
3788 Instruction syntax:
3789 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3790
3791 @param VmPtr A pointer to a VM context.
3792 @param Op1 Operand 1 from the instruction
3793 @param Op2 Operand 2 from the instruction
3794
3795 @return Op1 AND Op2
3796
3797 **/
3798 UINT64
3799 ExecuteAND (
3800 IN VM_CONTEXT *VmPtr,
3801 IN UINT64 Op1,
3802 IN UINT64 Op2
3803 )
3804 {
3805 return Op1 & Op2;
3806 }
3807
3808
3809 /**
3810 Execute the EBC OR instruction.
3811
3812 Instruction syntax:
3813 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3814
3815 @param VmPtr A pointer to a VM context.
3816 @param Op1 Operand 1 from the instruction
3817 @param Op2 Operand 2 from the instruction
3818
3819 @return Op1 OR Op2
3820
3821 **/
3822 UINT64
3823 ExecuteOR (
3824 IN VM_CONTEXT *VmPtr,
3825 IN UINT64 Op1,
3826 IN UINT64 Op2
3827 )
3828 {
3829 return Op1 | Op2;
3830 }
3831
3832
3833 /**
3834 Execute the EBC XOR instruction.
3835
3836 Instruction syntax:
3837 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3838
3839 @param VmPtr A pointer to a VM context.
3840 @param Op1 Operand 1 from the instruction
3841 @param Op2 Operand 2 from the instruction
3842
3843 @return Op1 XOR Op2
3844
3845 **/
3846 UINT64
3847 ExecuteXOR (
3848 IN VM_CONTEXT *VmPtr,
3849 IN UINT64 Op1,
3850 IN UINT64 Op2
3851 )
3852 {
3853 return Op1 ^ Op2;
3854 }
3855
3856
3857 /**
3858 Execute the EBC SHL shift left instruction.
3859
3860 Instruction syntax:
3861 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3862
3863 @param VmPtr A pointer to a VM context.
3864 @param Op1 Operand 1 from the instruction
3865 @param Op2 Operand 2 from the instruction
3866
3867 @return Op1 << Op2
3868
3869 **/
3870 UINT64
3871 ExecuteSHL (
3872 IN VM_CONTEXT *VmPtr,
3873 IN UINT64 Op1,
3874 IN UINT64 Op2
3875 )
3876 {
3877 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3878 return LShiftU64 (Op1, (UINTN)Op2);
3879 } else {
3880 return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));
3881 }
3882 }
3883
3884
3885 /**
3886 Execute the EBC SHR instruction.
3887
3888 Instruction syntax:
3889 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3890
3891 @param VmPtr A pointer to a VM context.
3892 @param Op1 Operand 1 from the instruction
3893 @param Op2 Operand 2 from the instruction
3894
3895 @return Op1 >> Op2 (unsigned operands)
3896
3897 **/
3898 UINT64
3899 ExecuteSHR (
3900 IN VM_CONTEXT *VmPtr,
3901 IN UINT64 Op1,
3902 IN UINT64 Op2
3903 )
3904 {
3905 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3906 return RShiftU64 (Op1, (UINTN)Op2);
3907 } else {
3908 return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);
3909 }
3910 }
3911
3912
3913 /**
3914 Execute the EBC ASHR instruction.
3915
3916 Instruction syntax:
3917 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3918
3919 @param VmPtr A pointer to a VM context.
3920 @param Op1 Operand 1 from the instruction
3921 @param Op2 Operand 2 from the instruction
3922
3923 @return Op1 >> Op2 (signed)
3924
3925 **/
3926 UINT64
3927 ExecuteASHR (
3928 IN VM_CONTEXT *VmPtr,
3929 IN UINT64 Op1,
3930 IN UINT64 Op2
3931 )
3932 {
3933 if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
3934 return ARShiftU64 (Op1, (UINTN)Op2);
3935 } else {
3936 return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));
3937 }
3938 }
3939
3940
3941 /**
3942 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3943
3944 Instruction syntax:
3945 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3946
3947 @param VmPtr A pointer to a VM context.
3948 @param Op1 Operand 1 from the instruction
3949 @param Op2 Operand 2 from the instruction
3950
3951 @return (INT64)(INT8)Op2
3952
3953 **/
3954 UINT64
3955 ExecuteEXTNDB (
3956 IN VM_CONTEXT *VmPtr,
3957 IN UINT64 Op1,
3958 IN UINT64 Op2
3959 )
3960 {
3961 INT8 Data8;
3962 INT64 Data64;
3963 //
3964 // Convert to byte, then return as 64-bit signed value to let compiler
3965 // sign-extend the value
3966 //
3967 Data8 = (INT8) Op2;
3968 Data64 = (INT64) Data8;
3969
3970 return (UINT64) Data64;
3971 }
3972
3973
3974 /**
3975 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
3976
3977 Instruction syntax:
3978 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
3979
3980 @param VmPtr A pointer to a VM context.
3981 @param Op1 Operand 1 from the instruction
3982 @param Op2 Operand 2 from the instruction
3983
3984 @return (INT64)(INT16)Op2
3985
3986 **/
3987 UINT64
3988 ExecuteEXTNDW (
3989 IN VM_CONTEXT *VmPtr,
3990 IN UINT64 Op1,
3991 IN UINT64 Op2
3992 )
3993 {
3994 INT16 Data16;
3995 INT64 Data64;
3996 //
3997 // Convert to word, then return as 64-bit signed value to let compiler
3998 // sign-extend the value
3999 //
4000 Data16 = (INT16) Op2;
4001 Data64 = (INT64) Data16;
4002
4003 return (UINT64) Data64;
4004 }
4005 //
4006 // Execute the EBC EXTNDD instruction.
4007 //
4008 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4009 // EXTNDD Dest, Source
4010 //
4011 // Operation: Dest <- SignExtended((DWORD)Source))
4012 //
4013
4014 /**
4015 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4016
4017 Instruction syntax:
4018 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4019
4020 @param VmPtr A pointer to a VM context.
4021 @param Op1 Operand 1 from the instruction
4022 @param Op2 Operand 2 from the instruction
4023
4024 @return (INT64)(INT32)Op2
4025
4026 **/
4027 UINT64
4028 ExecuteEXTNDD (
4029 IN VM_CONTEXT *VmPtr,
4030 IN UINT64 Op1,
4031 IN UINT64 Op2
4032 )
4033 {
4034 INT32 Data32;
4035 INT64 Data64;
4036 //
4037 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4038 // sign-extend the value
4039 //
4040 Data32 = (INT32) Op2;
4041 Data64 = (INT64) Data32;
4042
4043 return (UINT64) Data64;
4044 }
4045
4046
4047 /**
4048 Execute all the EBC signed data manipulation instructions.
4049 Since the EBC data manipulation instructions all have the same basic form,
4050 they can share the code that does the fetch of operands and the write-back
4051 of the result. This function performs the fetch of the operands (even if
4052 both are not needed to be fetched, like NOT instruction), dispatches to the
4053 appropriate subfunction, then writes back the returned result.
4054
4055 Format:
4056 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4057
4058 @param VmPtr A pointer to VM context.
4059
4060 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4061 @retval EFI_SUCCESS The instruction is executed successfully.
4062
4063 **/
4064 EFI_STATUS
4065 ExecuteSignedDataManip (
4066 IN VM_CONTEXT *VmPtr
4067 )
4068 {
4069 //
4070 // Just call the data manipulation function with a flag indicating this
4071 // is a signed operation.
4072 //
4073 return ExecuteDataManip (VmPtr, TRUE);
4074 }
4075
4076
4077 /**
4078 Execute all the EBC unsigned data manipulation instructions.
4079 Since the EBC data manipulation instructions all have the same basic form,
4080 they can share the code that does the fetch of operands and the write-back
4081 of the result. This function performs the fetch of the operands (even if
4082 both are not needed to be fetched, like NOT instruction), dispatches to the
4083 appropriate subfunction, then writes back the returned result.
4084
4085 Format:
4086 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4087
4088 @param VmPtr A pointer to VM context.
4089
4090 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4091 @retval EFI_SUCCESS The instruction is executed successfully.
4092
4093 **/
4094 EFI_STATUS
4095 ExecuteUnsignedDataManip (
4096 IN VM_CONTEXT *VmPtr
4097 )
4098 {
4099 //
4100 // Just call the data manipulation function with a flag indicating this
4101 // is not a signed operation.
4102 //
4103 return ExecuteDataManip (VmPtr, FALSE);
4104 }
4105
4106
4107 /**
4108 Execute all the EBC data manipulation instructions.
4109 Since the EBC data manipulation instructions all have the same basic form,
4110 they can share the code that does the fetch of operands and the write-back
4111 of the result. This function performs the fetch of the operands (even if
4112 both are not needed to be fetched, like NOT instruction), dispatches to the
4113 appropriate subfunction, then writes back the returned result.
4114
4115 Format:
4116 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4117
4118 @param VmPtr A pointer to VM context.
4119 @param IsSignedOp Indicates whether the operand is signed or not.
4120
4121 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4122 @retval EFI_SUCCESS The instruction is executed successfully.
4123
4124 **/
4125 EFI_STATUS
4126 ExecuteDataManip (
4127 IN VM_CONTEXT *VmPtr,
4128 IN BOOLEAN IsSignedOp
4129 )
4130 {
4131 UINT8 Opcode;
4132 INT16 Index16;
4133 UINT8 Operands;
4134 UINT8 Size;
4135 UINT64 Op1;
4136 UINT64 Op2;
4137
4138 //
4139 // Get opcode and operands
4140 //
4141 Opcode = GETOPCODE (VmPtr);
4142 Operands = GETOPERANDS (VmPtr);
4143
4144 //
4145 // Determine if we have immediate data by the opcode
4146 //
4147 if ((Opcode & DATAMANIP_M_IMMDATA) != 0) {
4148 //
4149 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4150 //
4151 if (OPERAND2_INDIRECT (Operands)) {
4152 Index16 = VmReadIndex16 (VmPtr, 2);
4153 } else {
4154 Index16 = VmReadImmed16 (VmPtr, 2);
4155 }
4156
4157 Size = 4;
4158 } else {
4159 Index16 = 0;
4160 Size = 2;
4161 }
4162 //
4163 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4164 //
4165 Op2 = (UINT64) VmPtr->R[OPERAND2_REGNUM (Operands)] + Index16;
4166 if (OPERAND2_INDIRECT (Operands)) {
4167 //
4168 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4169 //
4170 if ((Opcode & DATAMANIP_M_64) != 0) {
4171 Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);
4172 } else {
4173 //
4174 // Read as signed value where appropriate.
4175 //
4176 if (IsSignedOp) {
4177 Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));
4178 } else {
4179 Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);
4180 }
4181 }
4182 } else {
4183 if ((Opcode & DATAMANIP_M_64) == 0) {
4184 if (IsSignedOp) {
4185 Op2 = (UINT64) (INT64) ((INT32) Op2);
4186 } else {
4187 Op2 = (UINT64) ((UINT32) Op2);
4188 }
4189 }
4190 }
4191 //
4192 // Get operand1 (destination and sometimes also an actual operand)
4193 // of form {@}R1
4194 //
4195 Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];
4196 if (OPERAND1_INDIRECT (Operands)) {
4197 if ((Opcode & DATAMANIP_M_64) != 0) {
4198 Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);
4199 } else {
4200 if (IsSignedOp) {
4201 Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));
4202 } else {
4203 Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);
4204 }
4205 }
4206 } else {
4207 if ((Opcode & DATAMANIP_M_64) == 0) {
4208 if (IsSignedOp) {
4209 Op1 = (UINT64) (INT64) ((INT32) Op1);
4210 } else {
4211 Op1 = (UINT64) ((UINT32) Op1);
4212 }
4213 }
4214 }
4215 //
4216 // Dispatch to the computation function
4217 //
4218 if (((Opcode & OPCODE_M_OPCODE) - OPCODE_NOT) >=
4219 (sizeof (mDataManipDispatchTable) / sizeof (mDataManipDispatchTable[0]))
4220 ) {
4221 EbcDebugSignalException (
4222 EXCEPT_EBC_INVALID_OPCODE,
4223 EXCEPTION_FLAG_ERROR,
4224 VmPtr
4225 );
4226 //
4227 // Advance and return
4228 //
4229 VmPtr->Ip += Size;
4230 return EFI_UNSUPPORTED;
4231 } else {
4232 Op2 = mDataManipDispatchTable[(Opcode & OPCODE_M_OPCODE) - OPCODE_NOT](VmPtr, Op1, Op2);
4233 }
4234 //
4235 // Write back the result.
4236 //
4237 if (OPERAND1_INDIRECT (Operands)) {
4238 Op1 = VmPtr->R[OPERAND1_REGNUM (Operands)];
4239 if ((Opcode & DATAMANIP_M_64) != 0) {
4240 VmWriteMem64 (VmPtr, (UINTN) Op1, Op2);
4241 } else {
4242 VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) Op2);
4243 }
4244 } else {
4245 //
4246 // Storage back to a register. Write back, clearing upper bits (as per
4247 // the specification) if 32-bit operation.
4248 //
4249 VmPtr->R[OPERAND1_REGNUM (Operands)] = Op2;
4250 if ((Opcode & DATAMANIP_M_64) == 0) {
4251 VmPtr->R[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF;
4252 }
4253 }
4254 //
4255 // Advance the instruction pointer
4256 //
4257 VmPtr->Ip += Size;
4258 return EFI_SUCCESS;
4259 }
4260
4261
4262 /**
4263 Execute the EBC LOADSP instruction.
4264
4265 Instruction syntax:
4266 LOADSP SP1, R2
4267
4268 @param VmPtr A pointer to a VM context.
4269
4270 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4271 @retval EFI_SUCCESS The instruction is executed successfully.
4272
4273 **/
4274 EFI_STATUS
4275 ExecuteLOADSP (
4276 IN VM_CONTEXT *VmPtr
4277 )
4278 {
4279 UINT8 Operands;
4280
4281 //
4282 // Get the operands
4283 //
4284 Operands = GETOPERANDS (VmPtr);
4285
4286 //
4287 // Do the operation
4288 //
4289 switch (OPERAND1_REGNUM (Operands)) {
4290 //
4291 // Set flags
4292 //
4293 case 0:
4294 //
4295 // Spec states that this instruction will not modify reserved bits in
4296 // the flags register.
4297 //
4298 VmPtr->Flags = (VmPtr->Flags &~VMFLAGS_ALL_VALID) | (VmPtr->R[OPERAND2_REGNUM (Operands)] & VMFLAGS_ALL_VALID);
4299 break;
4300
4301 default:
4302 EbcDebugSignalException (
4303 EXCEPT_EBC_INSTRUCTION_ENCODING,
4304 EXCEPTION_FLAG_WARNING,
4305 VmPtr
4306 );
4307 VmPtr->Ip += 2;
4308 return EFI_UNSUPPORTED;
4309 }
4310
4311 VmPtr->Ip += 2;
4312 return EFI_SUCCESS;
4313 }
4314
4315
4316 /**
4317 Execute the EBC STORESP instruction.
4318
4319 Instruction syntax:
4320 STORESP Rx, FLAGS|IP
4321
4322 @param VmPtr A pointer to a VM context.
4323
4324 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4325 @retval EFI_SUCCESS The instruction is executed successfully.
4326
4327 **/
4328 EFI_STATUS
4329 ExecuteSTORESP (
4330 IN VM_CONTEXT *VmPtr
4331 )
4332 {
4333 UINT8 Operands;
4334
4335 //
4336 // Get the operands
4337 //
4338 Operands = GETOPERANDS (VmPtr);
4339
4340 //
4341 // Do the operation
4342 //
4343 switch (OPERAND2_REGNUM (Operands)) {
4344 //
4345 // Get flags
4346 //
4347 case 0:
4348 //
4349 // Retrieve the value in the flags register, then clear reserved bits
4350 //
4351 VmPtr->R[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID);
4352 break;
4353
4354 //
4355 // Get IP -- address of following instruction
4356 //
4357 case 1:
4358 VmPtr->R[OPERAND1_REGNUM (Operands)] = (UINT64) (UINTN) VmPtr->Ip + 2;
4359 break;
4360
4361 default:
4362 EbcDebugSignalException (
4363 EXCEPT_EBC_INSTRUCTION_ENCODING,
4364 EXCEPTION_FLAG_WARNING,
4365 VmPtr
4366 );
4367 VmPtr->Ip += 2;
4368 return EFI_UNSUPPORTED;
4369 break;
4370 }
4371
4372 VmPtr->Ip += 2;
4373 return EFI_SUCCESS;
4374 }
4375
4376
4377 /**
4378 Decode a 16-bit index to determine the offset. Given an index value:
4379
4380 b15 - sign bit
4381 b14:12 - number of bits in this index assigned to natural units (=a)
4382 ba:11 - constant units = ConstUnits
4383 b0:a - natural units = NaturalUnits
4384
4385 Given this info, the offset can be computed by:
4386 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4387
4388 Max offset is achieved with index = 0x7FFF giving an offset of
4389 0x27B (32-bit machine) or 0x477 (64-bit machine).
4390 Min offset is achieved with index =
4391
4392 @param VmPtr A pointer to VM context.
4393 @param CodeOffset Offset from IP of the location of the 16-bit index
4394 to decode.
4395
4396 @return The decoded offset.
4397
4398 **/
4399 INT16
4400 VmReadIndex16 (
4401 IN VM_CONTEXT *VmPtr,
4402 IN UINT32 CodeOffset
4403 )
4404 {
4405 UINT16 Index;
4406 INT16 Offset;
4407 INT16 ConstUnits;
4408 INT16 NaturalUnits;
4409 INT16 NBits;
4410 INT16 Mask;
4411
4412 //
4413 // First read the index from the code stream
4414 //
4415 Index = VmReadCode16 (VmPtr, CodeOffset);
4416
4417 //
4418 // Get the mask for NaturalUnits. First get the number of bits from the index.
4419 //
4420 NBits = (INT16) ((Index & 0x7000) >> 12);
4421
4422 //
4423 // Scale it for 16-bit indexes
4424 //
4425 NBits *= 2;
4426
4427 //
4428 // Now using the number of bits, create a mask.
4429 //
4430 Mask = (INT16) ((INT16)~0 << NBits);
4431
4432 //
4433 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4434 //
4435 NaturalUnits = (INT16) (Index &~Mask);
4436
4437 //
4438 // Now compute ConstUnits
4439 //
4440 ConstUnits = (INT16) (((Index &~0xF000) & Mask) >> NBits);
4441
4442 Offset = (INT16) (NaturalUnits * sizeof (UINTN) + ConstUnits);
4443
4444 //
4445 // Now set the sign
4446 //
4447 if ((Index & 0x8000) != 0) {
4448 //
4449 // Do it the hard way to work around a bogus compiler warning
4450 //
4451 // Offset = -1 * Offset;
4452 //
4453 Offset = (INT16) ((INT32) Offset * -1);
4454 }
4455
4456 return Offset;
4457 }
4458
4459
4460 /**
4461 Decode a 32-bit index to determine the offset.
4462
4463 @param VmPtr A pointer to VM context.
4464 @param CodeOffset Offset from IP of the location of the 32-bit index
4465 to decode.
4466
4467 @return Converted index per EBC VM specification.
4468
4469 **/
4470 INT32
4471 VmReadIndex32 (
4472 IN VM_CONTEXT *VmPtr,
4473 IN UINT32 CodeOffset
4474 )
4475 {
4476 UINT32 Index;
4477 INT32 Offset;
4478 INT32 ConstUnits;
4479 INT32 NaturalUnits;
4480 INT32 NBits;
4481 INT32 Mask;
4482
4483 Index = VmReadImmed32 (VmPtr, CodeOffset);
4484
4485 //
4486 // Get the mask for NaturalUnits. First get the number of bits from the index.
4487 //
4488 NBits = (Index & 0x70000000) >> 28;
4489
4490 //
4491 // Scale it for 32-bit indexes
4492 //
4493 NBits *= 4;
4494
4495 //
4496 // Now using the number of bits, create a mask.
4497 //
4498 Mask = (INT32)~0 << NBits;
4499
4500 //
4501 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4502 //
4503 NaturalUnits = Index &~Mask;
4504
4505 //
4506 // Now compute ConstUnits
4507 //
4508 ConstUnits = ((Index &~0xF0000000) & Mask) >> NBits;
4509
4510 Offset = NaturalUnits * sizeof (UINTN) + ConstUnits;
4511
4512 //
4513 // Now set the sign
4514 //
4515 if ((Index & 0x80000000) != 0) {
4516 Offset = Offset * -1;
4517 }
4518
4519 return Offset;
4520 }
4521
4522
4523 /**
4524 Decode a 64-bit index to determine the offset.
4525
4526 @param VmPtr A pointer to VM context.s
4527 @param CodeOffset Offset from IP of the location of the 64-bit index
4528 to decode.
4529
4530 @return Converted index per EBC VM specification
4531
4532 **/
4533 INT64
4534 VmReadIndex64 (
4535 IN VM_CONTEXT *VmPtr,
4536 IN UINT32 CodeOffset
4537 )
4538 {
4539 UINT64 Index;
4540 INT64 Offset;
4541 INT64 ConstUnits;
4542 INT64 NaturalUnits;
4543 INT64 NBits;
4544 INT64 Mask;
4545
4546 Index = VmReadCode64 (VmPtr, CodeOffset);
4547
4548 //
4549 // Get the mask for NaturalUnits. First get the number of bits from the index.
4550 //
4551 NBits = RShiftU64 ((Index & 0x7000000000000000ULL), 60);
4552
4553 //
4554 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4555 //
4556 NBits = LShiftU64 ((UINT64)NBits, 3);
4557
4558 //
4559 // Now using the number of bits, create a mask.
4560 //
4561 Mask = (LShiftU64 ((UINT64)~0, (UINTN)NBits));
4562
4563 //
4564 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4565 //
4566 NaturalUnits = Index &~Mask;
4567
4568 //
4569 // Now compute ConstUnits
4570 //
4571 ConstUnits = ARShiftU64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN)NBits);
4572
4573 Offset = MultU64x64 (NaturalUnits, sizeof (UINTN)) + ConstUnits;
4574
4575 //
4576 // Now set the sign
4577 //
4578 if ((Index & 0x8000000000000000ULL) != 0) {
4579 Offset = MultS64x64 (Offset, -1);
4580 }
4581
4582 return Offset;
4583 }
4584
4585
4586 /**
4587 Writes 8-bit data to memory address.
4588
4589 This routine is called by the EBC data
4590 movement instructions that write to memory. Since these writes
4591 may be to the stack, which looks like (high address on top) this,
4592
4593 [EBC entry point arguments]
4594 [VM stack]
4595 [EBC stack]
4596
4597 we need to detect all attempts to write to the EBC entry point argument
4598 stack area and adjust the address (which will initially point into the
4599 VM stack) to point into the EBC entry point arguments.
4600
4601 @param VmPtr A pointer to a VM context.
4602 @param Addr Adddress to write to.
4603 @param Data Value to write to Addr.
4604
4605 @retval EFI_SUCCESS The instruction is executed successfully.
4606 @retval Other Some error occurs when writing data to the address.
4607
4608 **/
4609 EFI_STATUS
4610 VmWriteMem8 (
4611 IN VM_CONTEXT *VmPtr,
4612 IN UINTN Addr,
4613 IN UINT8 Data
4614 )
4615 {
4616 //
4617 // Convert the address if it's in the stack gap
4618 //
4619 Addr = ConvertStackAddr (VmPtr, Addr);
4620 *(UINT8 *) Addr = Data;
4621 return EFI_SUCCESS;
4622 }
4623
4624 /**
4625 Writes 16-bit data to memory address.
4626
4627 This routine is called by the EBC data
4628 movement instructions that write to memory. Since these writes
4629 may be to the stack, which looks like (high address on top) this,
4630
4631 [EBC entry point arguments]
4632 [VM stack]
4633 [EBC stack]
4634
4635 we need to detect all attempts to write to the EBC entry point argument
4636 stack area and adjust the address (which will initially point into the
4637 VM stack) to point into the EBC entry point arguments.
4638
4639 @param VmPtr A pointer to a VM context.
4640 @param Addr Adddress to write to.
4641 @param Data Value to write to Addr.
4642
4643 @retval EFI_SUCCESS The instruction is executed successfully.
4644 @retval Other Some error occurs when writing data to the address.
4645
4646 **/
4647 EFI_STATUS
4648 VmWriteMem16 (
4649 IN VM_CONTEXT *VmPtr,
4650 IN UINTN Addr,
4651 IN UINT16 Data
4652 )
4653 {
4654 EFI_STATUS Status;
4655
4656 //
4657 // Convert the address if it's in the stack gap
4658 //
4659 Addr = ConvertStackAddr (VmPtr, Addr);
4660
4661 //
4662 // Do a simple write if aligned
4663 //
4664 if (IS_ALIGNED (Addr, sizeof (UINT16))) {
4665 *(UINT16 *) Addr = Data;
4666 } else {
4667 //
4668 // Write as two bytes
4669 //
4670 MemoryFence ();
4671 if ((Status = VmWriteMem8 (VmPtr, Addr, (UINT8) Data)) != EFI_SUCCESS) {
4672 return Status;
4673 }
4674
4675 MemoryFence ();
4676 if ((Status = VmWriteMem8 (VmPtr, Addr + 1, (UINT8) (Data >> 8))) != EFI_SUCCESS) {
4677 return Status;
4678 }
4679
4680 MemoryFence ();
4681 }
4682
4683 return EFI_SUCCESS;
4684 }
4685
4686
4687 /**
4688 Writes 32-bit data to memory address.
4689
4690 This routine is called by the EBC data
4691 movement instructions that write to memory. Since these writes
4692 may be to the stack, which looks like (high address on top) this,
4693
4694 [EBC entry point arguments]
4695 [VM stack]
4696 [EBC stack]
4697
4698 we need to detect all attempts to write to the EBC entry point argument
4699 stack area and adjust the address (which will initially point into the
4700 VM stack) to point into the EBC entry point arguments.
4701
4702 @param VmPtr A pointer to a VM context.
4703 @param Addr Adddress to write to.
4704 @param Data Value to write to Addr.
4705
4706 @retval EFI_SUCCESS The instruction is executed successfully.
4707 @retval Other Some error occurs when writing data to the address.
4708
4709 **/
4710 EFI_STATUS
4711 VmWriteMem32 (
4712 IN VM_CONTEXT *VmPtr,
4713 IN UINTN Addr,
4714 IN UINT32 Data
4715 )
4716 {
4717 EFI_STATUS Status;
4718
4719 //
4720 // Convert the address if it's in the stack gap
4721 //
4722 Addr = ConvertStackAddr (VmPtr, Addr);
4723
4724 //
4725 // Do a simple write if aligned
4726 //
4727 if (IS_ALIGNED (Addr, sizeof (UINT32))) {
4728 *(UINT32 *) Addr = Data;
4729 } else {
4730 //
4731 // Write as two words
4732 //
4733 MemoryFence ();
4734 if ((Status = VmWriteMem16 (VmPtr, Addr, (UINT16) Data)) != EFI_SUCCESS) {
4735 return Status;
4736 }
4737
4738 MemoryFence ();
4739 if ((Status = VmWriteMem16 (VmPtr, Addr + sizeof (UINT16), (UINT16) (Data >> 16))) != EFI_SUCCESS) {
4740 return Status;
4741 }
4742
4743 MemoryFence ();
4744 }
4745
4746 return EFI_SUCCESS;
4747 }
4748
4749
4750 /**
4751 Writes 64-bit data to memory address.
4752
4753 This routine is called by the EBC data
4754 movement instructions that write to memory. Since these writes
4755 may be to the stack, which looks like (high address on top) this,
4756
4757 [EBC entry point arguments]
4758 [VM stack]
4759 [EBC stack]
4760
4761 we need to detect all attempts to write to the EBC entry point argument
4762 stack area and adjust the address (which will initially point into the
4763 VM stack) to point into the EBC entry point arguments.
4764
4765 @param VmPtr A pointer to a VM context.
4766 @param Addr Adddress to write to.
4767 @param Data Value to write to Addr.
4768
4769 @retval EFI_SUCCESS The instruction is executed successfully.
4770 @retval Other Some error occurs when writing data to the address.
4771
4772 **/
4773 EFI_STATUS
4774 VmWriteMem64 (
4775 IN VM_CONTEXT *VmPtr,
4776 IN UINTN Addr,
4777 IN UINT64 Data
4778 )
4779 {
4780 EFI_STATUS Status;
4781 UINT32 Data32;
4782
4783 //
4784 // Convert the address if it's in the stack gap
4785 //
4786 Addr = ConvertStackAddr (VmPtr, Addr);
4787
4788 //
4789 // Do a simple write if aligned
4790 //
4791 if (IS_ALIGNED (Addr, sizeof (UINT64))) {
4792 *(UINT64 *) Addr = Data;
4793 } else {
4794 //
4795 // Write as two 32-bit words
4796 //
4797 MemoryFence ();
4798 if ((Status = VmWriteMem32 (VmPtr, Addr, (UINT32) Data)) != EFI_SUCCESS) {
4799 return Status;
4800 }
4801
4802 MemoryFence ();
4803 Data32 = (UINT32) (((UINT32 *) &Data)[1]);
4804 if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), Data32)) != EFI_SUCCESS) {
4805 return Status;
4806 }
4807
4808 MemoryFence ();
4809 }
4810
4811 return EFI_SUCCESS;
4812 }
4813
4814
4815 /**
4816 Writes UINTN data to memory address.
4817
4818 This routine is called by the EBC data
4819 movement instructions that write to memory. Since these writes
4820 may be to the stack, which looks like (high address on top) this,
4821
4822 [EBC entry point arguments]
4823 [VM stack]
4824 [EBC stack]
4825
4826 we need to detect all attempts to write to the EBC entry point argument
4827 stack area and adjust the address (which will initially point into the
4828 VM stack) to point into the EBC entry point arguments.
4829
4830 @param VmPtr A pointer to a VM context.
4831 @param Addr Adddress to write to.
4832 @param Data Value to write to Addr.
4833
4834 @retval EFI_SUCCESS The instruction is executed successfully.
4835 @retval Other Some error occurs when writing data to the address.
4836
4837 **/
4838 EFI_STATUS
4839 VmWriteMemN (
4840 IN VM_CONTEXT *VmPtr,
4841 IN UINTN Addr,
4842 IN UINTN Data
4843 )
4844 {
4845 EFI_STATUS Status;
4846 UINTN Index;
4847
4848 Status = EFI_SUCCESS;
4849
4850 //
4851 // Convert the address if it's in the stack gap
4852 //
4853 Addr = ConvertStackAddr (VmPtr, Addr);
4854
4855 //
4856 // Do a simple write if aligned
4857 //
4858 if (IS_ALIGNED (Addr, sizeof (UINTN))) {
4859 *(UINTN *) Addr = Data;
4860 } else {
4861 for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
4862 MemoryFence ();
4863 Status = VmWriteMem32 (VmPtr, Addr + Index * sizeof (UINT32), (UINT32) Data);
4864 MemoryFence ();
4865 Data = (UINTN)RShiftU64 ((UINT64)Data, 32);
4866 }
4867 }
4868
4869 return Status;
4870 }
4871
4872
4873 /**
4874 Reads 8-bit immediate value at the offset.
4875
4876 This routine is called by the EBC execute
4877 functions to read EBC immediate values from the code stream.
4878 Since we can't assume alignment, each tries to read in the biggest
4879 chunks size available, but will revert to smaller reads if necessary.
4880
4881 @param VmPtr A pointer to a VM context.
4882 @param Offset offset from IP of the code bytes to read.
4883
4884 @return Signed data of the requested size from the specified address.
4885
4886 **/
4887 INT8
4888 VmReadImmed8 (
4889 IN VM_CONTEXT *VmPtr,
4890 IN UINT32 Offset
4891 )
4892 {
4893 //
4894 // Simply return the data in flat memory space
4895 //
4896 return * (INT8 *) (VmPtr->Ip + Offset);
4897 }
4898
4899 /**
4900 Reads 16-bit immediate value at the offset.
4901
4902 This routine is called by the EBC execute
4903 functions to read EBC immediate values from the code stream.
4904 Since we can't assume alignment, each tries to read in the biggest
4905 chunks size available, but will revert to smaller reads if necessary.
4906
4907 @param VmPtr A pointer to a VM context.
4908 @param Offset offset from IP of the code bytes to read.
4909
4910 @return Signed data of the requested size from the specified address.
4911
4912 **/
4913 INT16
4914 VmReadImmed16 (
4915 IN VM_CONTEXT *VmPtr,
4916 IN UINT32 Offset
4917 )
4918 {
4919 //
4920 // Read direct if aligned
4921 //
4922 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
4923 return * (INT16 *) (VmPtr->Ip + Offset);
4924 } else {
4925 //
4926 // All code word reads should be aligned
4927 //
4928 EbcDebugSignalException (
4929 EXCEPT_EBC_ALIGNMENT_CHECK,
4930 EXCEPTION_FLAG_WARNING,
4931 VmPtr
4932 );
4933 }
4934 //
4935 // Return unaligned data
4936 //
4937 return (INT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
4938 }
4939
4940
4941 /**
4942 Reads 32-bit immediate value at the offset.
4943
4944 This routine is called by the EBC execute
4945 functions to read EBC immediate values from the code stream.
4946 Since we can't assume alignment, each tries to read in the biggest
4947 chunks size available, but will revert to smaller reads if necessary.
4948
4949 @param VmPtr A pointer to a VM context.
4950 @param Offset offset from IP of the code bytes to read.
4951
4952 @return Signed data of the requested size from the specified address.
4953
4954 **/
4955 INT32
4956 VmReadImmed32 (
4957 IN VM_CONTEXT *VmPtr,
4958 IN UINT32 Offset
4959 )
4960 {
4961 UINT32 Data;
4962
4963 //
4964 // Read direct if aligned
4965 //
4966 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
4967 return * (INT32 *) (VmPtr->Ip + Offset);
4968 }
4969 //
4970 // Return unaligned data
4971 //
4972 Data = (UINT32) VmReadCode16 (VmPtr, Offset);
4973 Data |= (UINT32) (VmReadCode16 (VmPtr, Offset + 2) << 16);
4974 return Data;
4975 }
4976
4977
4978 /**
4979 Reads 64-bit immediate value at the offset.
4980
4981 This routine is called by the EBC execute
4982 functions to read EBC immediate values from the code stream.
4983 Since we can't assume alignment, each tries to read in the biggest
4984 chunks size available, but will revert to smaller reads if necessary.
4985
4986 @param VmPtr A pointer to a VM context.
4987 @param Offset offset from IP of the code bytes to read.
4988
4989 @return Signed data of the requested size from the specified address.
4990
4991 **/
4992 INT64
4993 VmReadImmed64 (
4994 IN VM_CONTEXT *VmPtr,
4995 IN UINT32 Offset
4996 )
4997 {
4998 UINT64 Data64;
4999 UINT32 Data32;
5000 UINT8 *Ptr;
5001
5002 //
5003 // Read direct if aligned
5004 //
5005 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
5006 return * (UINT64 *) (VmPtr->Ip + Offset);
5007 }
5008 //
5009 // Return unaligned data.
5010 //
5011 Ptr = (UINT8 *) &Data64;
5012 Data32 = VmReadCode32 (VmPtr, Offset);
5013 *(UINT32 *) Ptr = Data32;
5014 Ptr += sizeof (Data32);
5015 Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
5016 *(UINT32 *) Ptr = Data32;
5017 return Data64;
5018 }
5019
5020
5021 /**
5022 Reads 16-bit unsinged data from the code stream.
5023
5024 This routine provides the ability to read raw unsigned data from the code
5025 stream.
5026
5027 @param VmPtr A pointer to VM context
5028 @param Offset Offset from current IP to the raw data to read.
5029
5030 @return The raw unsigned 16-bit value from the code stream.
5031
5032 **/
5033 UINT16
5034 VmReadCode16 (
5035 IN VM_CONTEXT *VmPtr,
5036 IN UINT32 Offset
5037 )
5038 {
5039 //
5040 // Read direct if aligned
5041 //
5042 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
5043 return * (UINT16 *) (VmPtr->Ip + Offset);
5044 } else {
5045 //
5046 // All code word reads should be aligned
5047 //
5048 EbcDebugSignalException (
5049 EXCEPT_EBC_ALIGNMENT_CHECK,
5050 EXCEPTION_FLAG_WARNING,
5051 VmPtr
5052 );
5053 }
5054 //
5055 // Return unaligned data
5056 //
5057 return (UINT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
5058 }
5059
5060
5061 /**
5062 Reads 32-bit unsinged data from the code stream.
5063
5064 This routine provides the ability to read raw unsigned data from the code
5065 stream.
5066
5067 @param VmPtr A pointer to VM context
5068 @param Offset Offset from current IP to the raw data to read.
5069
5070 @return The raw unsigned 32-bit value from the code stream.
5071
5072 **/
5073 UINT32
5074 VmReadCode32 (
5075 IN VM_CONTEXT *VmPtr,
5076 IN UINT32 Offset
5077 )
5078 {
5079 UINT32 Data;
5080 //
5081 // Read direct if aligned
5082 //
5083 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
5084 return * (UINT32 *) (VmPtr->Ip + Offset);
5085 }
5086 //
5087 // Return unaligned data
5088 //
5089 Data = (UINT32) VmReadCode16 (VmPtr, Offset);
5090 Data |= (VmReadCode16 (VmPtr, Offset + 2) << 16);
5091 return Data;
5092 }
5093
5094
5095 /**
5096 Reads 64-bit unsinged data from the code stream.
5097
5098 This routine provides the ability to read raw unsigned data from the code
5099 stream.
5100
5101 @param VmPtr A pointer to VM context
5102 @param Offset Offset from current IP to the raw data to read.
5103
5104 @return The raw unsigned 64-bit value from the code stream.
5105
5106 **/
5107 UINT64
5108 VmReadCode64 (
5109 IN VM_CONTEXT *VmPtr,
5110 IN UINT32 Offset
5111 )
5112 {
5113 UINT64 Data64;
5114 UINT32 Data32;
5115 UINT8 *Ptr;
5116
5117 //
5118 // Read direct if aligned
5119 //
5120 if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
5121 return * (UINT64 *) (VmPtr->Ip + Offset);
5122 }
5123 //
5124 // Return unaligned data.
5125 //
5126 Ptr = (UINT8 *) &Data64;
5127 Data32 = VmReadCode32 (VmPtr, Offset);
5128 *(UINT32 *) Ptr = Data32;
5129 Ptr += sizeof (Data32);
5130 Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
5131 *(UINT32 *) Ptr = Data32;
5132 return Data64;
5133 }
5134
5135
5136 /**
5137 Reads 8-bit data form the memory address.
5138
5139 @param VmPtr A pointer to VM context.
5140 @param Addr The memory address.
5141
5142 @return The 8-bit value from the memory adress.
5143
5144 **/
5145 UINT8
5146 VmReadMem8 (
5147 IN VM_CONTEXT *VmPtr,
5148 IN UINTN Addr
5149 )
5150 {
5151 //
5152 // Convert the address if it's in the stack gap
5153 //
5154 Addr = ConvertStackAddr (VmPtr, Addr);
5155 //
5156 // Simply return the data in flat memory space
5157 //
5158 return * (UINT8 *) Addr;
5159 }
5160
5161 /**
5162 Reads 16-bit data form the memory address.
5163
5164 @param VmPtr A pointer to VM context.
5165 @param Addr The memory address.
5166
5167 @return The 16-bit value from the memory adress.
5168
5169 **/
5170 UINT16
5171 VmReadMem16 (
5172 IN VM_CONTEXT *VmPtr,
5173 IN UINTN Addr
5174 )
5175 {
5176 //
5177 // Convert the address if it's in the stack gap
5178 //
5179 Addr = ConvertStackAddr (VmPtr, Addr);
5180 //
5181 // Read direct if aligned
5182 //
5183 if (IS_ALIGNED (Addr, sizeof (UINT16))) {
5184 return * (UINT16 *) Addr;
5185 }
5186 //
5187 // Return unaligned data
5188 //
5189 return (UINT16) (*(UINT8 *) Addr + (*(UINT8 *) (Addr + 1) << 8));
5190 }
5191
5192 /**
5193 Reads 32-bit data form the memory address.
5194
5195 @param VmPtr A pointer to VM context.
5196 @param Addr The memory address.
5197
5198 @return The 32-bit value from the memory adress.
5199
5200 **/
5201 UINT32
5202 VmReadMem32 (
5203 IN VM_CONTEXT *VmPtr,
5204 IN UINTN Addr
5205 )
5206 {
5207 UINT32 Data;
5208
5209 //
5210 // Convert the address if it's in the stack gap
5211 //
5212 Addr = ConvertStackAddr (VmPtr, Addr);
5213 //
5214 // Read direct if aligned
5215 //
5216 if (IS_ALIGNED (Addr, sizeof (UINT32))) {
5217 return * (UINT32 *) Addr;
5218 }
5219 //
5220 // Return unaligned data
5221 //
5222 Data = (UINT32) VmReadMem16 (VmPtr, Addr);
5223 Data |= (VmReadMem16 (VmPtr, Addr + 2) << 16);
5224 return Data;
5225 }
5226
5227 /**
5228 Reads 64-bit data form the memory address.
5229
5230 @param VmPtr A pointer to VM context.
5231 @param Addr The memory address.
5232
5233 @return The 64-bit value from the memory adress.
5234
5235 **/
5236 UINT64
5237 VmReadMem64 (
5238 IN VM_CONTEXT *VmPtr,
5239 IN UINTN Addr
5240 )
5241 {
5242 UINT64 Data;
5243 UINT32 Data32;
5244
5245 //
5246 // Convert the address if it's in the stack gap
5247 //
5248 Addr = ConvertStackAddr (VmPtr, Addr);
5249
5250 //
5251 // Read direct if aligned
5252 //
5253 if (IS_ALIGNED (Addr, sizeof (UINT64))) {
5254 return * (UINT64 *) Addr;
5255 }
5256 //
5257 // Return unaligned data. Assume little endian.
5258 //
5259 Data = (UINT64) VmReadMem32 (VmPtr, Addr);
5260 Data32 = VmReadMem32 (VmPtr, Addr + sizeof (UINT32));
5261 *(UINT32 *) ((UINT32 *) &Data + 1) = Data32;
5262 return Data;
5263 }
5264
5265
5266 /**
5267 Given an address that EBC is going to read from or write to, return
5268 an appropriate address that accounts for a gap in the stack.
5269 The stack for this application looks like this (high addr on top)
5270 [EBC entry point arguments]
5271 [VM stack]
5272 [EBC stack]
5273 The EBC assumes that its arguments are at the top of its stack, which
5274 is where the VM stack is really. Therefore if the EBC does memory
5275 accesses into the VM stack area, then we need to convert the address
5276 to point to the EBC entry point arguments area. Do this here.
5277
5278 @param VmPtr A Pointer to VM context.
5279 @param Addr Address of interest
5280
5281 @return The unchanged address if it's not in the VM stack region. Otherwise,
5282 adjust for the stack gap and return the modified address.
5283
5284 **/
5285 UINTN
5286 ConvertStackAddr (
5287 IN VM_CONTEXT *VmPtr,
5288 IN UINTN Addr
5289 )
5290 {
5291 ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));
5292 return Addr;
5293 }
5294
5295
5296 /**
5297 Read a natural value from memory. May or may not be aligned.
5298
5299 @param VmPtr current VM context
5300 @param Addr the address to read from
5301
5302 @return The natural value at address Addr.
5303
5304 **/
5305 UINTN
5306 VmReadMemN (
5307 IN VM_CONTEXT *VmPtr,
5308 IN UINTN Addr
5309 )
5310 {
5311 UINTN Data;
5312 volatile UINT32 Size;
5313 UINT8 *FromPtr;
5314 UINT8 *ToPtr;
5315 //
5316 // Convert the address if it's in the stack gap
5317 //
5318 Addr = ConvertStackAddr (VmPtr, Addr);
5319 //
5320 // Read direct if aligned
5321 //
5322 if (IS_ALIGNED (Addr, sizeof (UINTN))) {
5323 return * (UINTN *) Addr;
5324 }
5325 //
5326 // Return unaligned data
5327 //
5328 Data = 0;
5329 FromPtr = (UINT8 *) Addr;
5330 ToPtr = (UINT8 *) &Data;
5331
5332 for (Size = 0; Size < sizeof (Data); Size++) {
5333 *ToPtr = *FromPtr;
5334 ToPtr++;
5335 FromPtr++;
5336 }
5337
5338 return Data;
5339 }
5340
5341 /**
5342 Returns the version of the EBC virtual machine.
5343
5344 @return The 64-bit version of EBC virtual machine.
5345
5346 **/
5347 UINT64
5348 GetVmVersion (
5349 VOID
5350 )
5351 {
5352 return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)));
5353 }