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