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