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