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