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