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