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