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