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