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