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