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