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