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