2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_emulator.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <palacios/vmm_decoder.h>
24 #include <palacios/vmm_paging.h>
25 #include <palacios/vmm_instr_emulator.h>
27 #ifndef DEBUG_EMULATOR
29 #define PrintDebug(fmt, args...)
33 static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size);
35 // We emulate up to the next 4KB page boundry
36 static int emulate_string_write_op(struct guest_info * info, struct x86_instr * dec_instr,
37 addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
38 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
40 uint_t emulation_length = 0;
41 uint_t emulation_iter_cnt = 0;
45 if (dec_instr->dst_operand.operand != write_gva) {
46 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
47 (void *)dec_instr->dst_operand.operand, (void *)write_gva);
51 emulation_length = ( (dec_instr->str_op_length < (0x1000 - PAGE_OFFSET_4KB(write_gva))) ?
52 dec_instr->str_op_length :
53 (0x1000 - PAGE_OFFSET_4KB(write_gva)));
55 /* ** Fix emulation length so that it doesn't overrun over the src page either ** */
56 emulation_iter_cnt = emulation_length / dec_instr->dst_operand.size;
57 tmp_rcx = emulation_iter_cnt;
59 if (dec_instr->op_type == V3_OP_MOVS) {
61 // figure out addresses here....
62 if (info->mem_mode == PHYSICAL_MEM) {
63 if (guest_pa_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
64 PrintError("Could not translate write Source (Physical) to host VA\n");
68 if (guest_va_to_host_va(info, dec_instr->src_operand.operand, &src_addr) == -1) {
69 PrintError("Could not translate write Source (Virtual) to host VA\n");
74 if (dec_instr->dst_operand.size == 1) {
75 movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
76 } else if (dec_instr->dst_operand.size == 2) {
77 movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
78 } else if (dec_instr->dst_operand.size == 4) {
79 movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
81 } else if (dec_instr->dst_operand.size == 8) {
82 movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
85 PrintError("Invalid operand length\n");
89 info->vm_regs.rdi += emulation_length;
90 info->vm_regs.rsi += emulation_length;
92 // RCX is only modified if the rep prefix is present
93 if (dec_instr->prefixes.rep == 1) {
94 info->vm_regs.rcx -= emulation_iter_cnt;
97 } else if (dec_instr->op_type == V3_OP_STOS) {
99 if (dec_instr->dst_operand.size == 1) {
100 stos8((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
101 } else if (dec_instr->dst_operand.size == 2) {
102 stos16((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
103 } else if (dec_instr->dst_operand.size == 4) {
104 stos32((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
106 } else if (dec_instr->dst_operand.size == 8) {
107 stos64((addr_t *)&dst_addr, (addr_t *)&(info->vm_regs.rax), &tmp_rcx, (addr_t *)&(info->ctrl_regs.rflags));
110 PrintError("Invalid operand length\n");
114 info->vm_regs.rdi += emulation_length;
116 // RCX is only modified if the rep prefix is present
117 if (dec_instr->prefixes.rep == 1) {
118 info->vm_regs.rcx -= emulation_iter_cnt;
122 PrintError("Unimplemented String operation\n");
126 if (write_fn(write_gpa, (void *)dst_addr, emulation_length, priv_data) != emulation_length) {
127 PrintError("Did not fully read hooked data\n");
131 if (emulation_length == dec_instr->str_op_length) {
132 info->rip += dec_instr->instr_length;
135 return emulation_length;
139 static int emulate_xchg_write_op(struct guest_info * info, struct x86_instr * dec_instr,
140 addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
141 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
144 addr_t em_dst_addr = 0;
147 PrintDebug("Emulating XCHG write\n");
149 if (dec_instr->src_operand.type == MEM_OPERAND) {
150 if (info->shdw_pg_mode == SHADOW_PAGING) {
151 if (dec_instr->src_operand.operand != write_gva) {
152 PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
153 (void *)dec_instr->src_operand.operand, (void *)write_gva);
159 } else if (dec_instr->src_operand.type == REG_OPERAND) {
160 src_addr = dec_instr->src_operand.operand;
162 src_addr = (addr_t)&(dec_instr->src_operand.operand);
167 if (dec_instr->dst_operand.type == MEM_OPERAND) {
168 if (info->shdw_pg_mode == SHADOW_PAGING) {
169 if (dec_instr->dst_operand.operand != write_gva) {
170 PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
171 (void *)dec_instr->dst_operand.operand, (void *)write_gva);
175 //check that the operand (GVA) maps to the the faulting GPA
178 em_dst_addr = dst_addr;
179 } else if (dec_instr->src_operand.type == REG_OPERAND) {
180 em_dst_addr = dec_instr->src_operand.operand;
182 em_dst_addr = (addr_t)&(dec_instr->src_operand.operand);
185 dst_op_len = dec_instr->dst_operand.size;
186 src_op_len = dec_instr->src_operand.size;
188 PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
189 (void *)dst_addr, (void *)src_addr);
192 if (run_op(info, dec_instr->op_type, src_addr, em_dst_addr, src_op_len, dst_op_len) == -1) {
193 PrintError("Instruction Emulation Failed\n");
197 if (write_fn(write_gpa, (void *)dst_addr, dst_op_len, priv_data) != dst_op_len) {
198 PrintError("Did not fully write hooked data\n");
202 info->rip += dec_instr->instr_length;
209 static int emulate_xchg_read_op(struct guest_info * info, struct x86_instr * dec_instr,
210 addr_t read_gva, addr_t read_gpa, addr_t src_addr,
211 int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
212 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
214 addr_t em_src_addr = 0;
215 addr_t em_dst_addr = 0;
219 PrintDebug("Emulating XCHG Read\n");
221 if (dec_instr->src_operand.type == MEM_OPERAND) {
222 if (dec_instr->src_operand.operand != read_gva) {
223 PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
224 (void *)dec_instr->src_operand.operand, (void *)read_gva);
228 em_src_addr = src_addr;
229 } else if (dec_instr->src_operand.type == REG_OPERAND) {
230 em_src_addr = dec_instr->src_operand.operand;
232 em_src_addr = (addr_t)&(dec_instr->src_operand.operand);
237 if (dec_instr->dst_operand.type == MEM_OPERAND) {
238 if (info->shdw_pg_mode == SHADOW_PAGING) {
239 if (dec_instr->dst_operand.operand != read_gva) {
240 PrintError("XCHG: Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
241 (void *)dec_instr->dst_operand.operand, (void *)read_gva);
245 //check that the operand (GVA) maps to the the faulting GPA
248 em_dst_addr = src_addr;
249 } else if (dec_instr->src_operand.type == REG_OPERAND) {
250 em_dst_addr = dec_instr->src_operand.operand;
252 em_dst_addr = (addr_t)&(dec_instr->src_operand.operand);
255 dst_op_len = dec_instr->dst_operand.size;
256 src_op_len = dec_instr->src_operand.size;
258 PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
259 (void *)em_dst_addr, (void *)em_src_addr);
262 if (read_fn(read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) {
263 PrintError("Did not fully read hooked data\n");
267 if (run_op(info, dec_instr->op_type, em_src_addr, em_dst_addr, src_op_len, dst_op_len) == -1) {
268 PrintError("Instruction Emulation Failed\n");
272 if (write_fn(read_gpa, (void *)src_addr, dst_op_len, priv_data) != dst_op_len) {
273 PrintError("Did not fully write hooked data\n");
277 info->rip += dec_instr->instr_length;
285 int v3_emulate_write_op(struct guest_info * info, addr_t write_gva, addr_t write_gpa, addr_t dst_addr,
286 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
288 struct x86_instr dec_instr;
295 PrintDebug("Emulating Write for instruction at %p\n", (void *)(addr_t)(info->rip));
296 PrintDebug("GVA=%p Dst_Addr=%p\n", (void *)write_gva, (void *)dst_addr);
298 if (info->mem_mode == PHYSICAL_MEM) {
299 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
301 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
308 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
309 PrintError("Decoding Error\n");
310 // Kick off single step emulator
315 * Instructions needing to be special cased.... *
317 if (dec_instr.is_str_op) {
318 return emulate_string_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr, write_fn, priv_data);
319 } else if (dec_instr.op_type == V3_OP_XCHG) {
320 return emulate_xchg_write_op(info, &dec_instr, write_gva, write_gpa, dst_addr, write_fn, priv_data);
324 if (info->shdw_pg_mode == SHADOW_PAGING) {
325 if ((dec_instr.dst_operand.type != MEM_OPERAND) ||
326 (dec_instr.dst_operand.operand != write_gva)) {
327 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",
328 (void *)dec_instr.dst_operand.operand, (void *)write_gva);
332 //check that the operand (GVA) maps to the the faulting GPA
336 if (dec_instr.src_operand.type == MEM_OPERAND) {
337 if (info->mem_mode == PHYSICAL_MEM) {
338 if (guest_pa_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) {
339 PrintError("Could not translate write Source (Physical) to host VA\n");
343 if (guest_va_to_host_va(info, dec_instr.src_operand.operand, &src_addr) == -1) {
344 PrintError("Could not translate write Source (Virtual) to host VA\n");
348 } else if (dec_instr.src_operand.type == REG_OPERAND) {
349 src_addr = dec_instr.src_operand.operand;
351 src_addr = (addr_t)&(dec_instr.src_operand.operand);
354 dst_op_len = dec_instr.dst_operand.size;
355 src_op_len = dec_instr.src_operand.size;
357 PrintDebug("Dst_Addr = %p, SRC operand = %p\n",
358 (void *)dst_addr, (void *)src_addr);
361 if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
362 PrintError("Instruction Emulation Failed\n");
366 if (write_fn(write_gpa, (void *)dst_addr, dst_op_len, priv_data) != dst_op_len) {
367 PrintError("Did not fully write hooked data\n");
371 info->rip += dec_instr.instr_length;
377 int v3_emulate_read_op(struct guest_info * info, addr_t read_gva, addr_t read_gpa, addr_t src_addr,
378 int (*read_fn)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
379 int (*write_fn)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
381 struct x86_instr dec_instr;
388 PrintDebug("Emulating Read for instruction at %p\n", (void *)(addr_t)(info->rip));
389 PrintDebug("GVA=%p\n", (void *)read_gva);
391 if (info->mem_mode == PHYSICAL_MEM) {
392 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
394 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
398 PrintError("Could not read instruction for Emulated Read at %p\n", (void *)(addr_t)(info->rip));
403 if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
404 PrintError("Decoding Error\n");
405 // Kick off single step emulator
409 if (dec_instr.is_str_op) {
410 PrintError("String operations not implemented on fully hooked regions\n");
412 } else if (dec_instr.op_type == V3_OP_XCHG) {
413 return emulate_xchg_read_op(info, &dec_instr, read_gva, read_gpa, src_addr, read_fn, write_fn, priv_data);
416 if (info->shdw_pg_mode == SHADOW_PAGING) {
417 if ((dec_instr.src_operand.type != MEM_OPERAND) ||
418 (dec_instr.src_operand.operand != read_gva)) {
419 PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p operand_type=%d\n",
420 (void *)dec_instr.src_operand.operand, (void *)read_gva, dec_instr.src_operand.type);
424 //check that the operand (GVA) maps to the the faulting GPA
427 if (dec_instr.dst_operand.type == MEM_OPERAND) {
428 if (info->mem_mode == PHYSICAL_MEM) {
429 if (guest_pa_to_host_va(info, dec_instr.dst_operand.operand, &dst_addr) == -1) {
430 PrintError("Could not translate Read Destination (Physical) to host VA\n");
434 if (guest_va_to_host_va(info, dec_instr.dst_operand.operand, &dst_addr) == -1) {
435 PrintError("Could not translate Read Destination (Virtual) to host VA\n");
439 } else if (dec_instr.dst_operand.type == REG_OPERAND) {
440 dst_addr = dec_instr.dst_operand.operand;
442 dst_addr = (addr_t)&(dec_instr.dst_operand.operand);
445 src_op_len = dec_instr.src_operand.size;
446 dst_op_len = dec_instr.dst_operand.size;
448 PrintDebug("Dst_Addr = %p, SRC Addr = %p\n",
449 (void *)dst_addr, (void *)src_addr);
451 if (read_fn(read_gpa, (void *)src_addr, src_op_len, priv_data) != src_op_len) {
452 PrintError("Did not fully read hooked data\n");
456 if (run_op(info, dec_instr.op_type, src_addr, dst_addr, src_op_len, dst_op_len) == -1) {
457 PrintError("Instruction Emulation Failed\n");
461 info->rip += dec_instr.instr_length;
471 static int run_op(struct guest_info * info, v3_op_type_t op_type, addr_t src_addr, addr_t dst_addr, int src_op_size, int dst_op_size) {
473 if (src_op_size == 1) {
474 PrintDebug("Executing 8 bit instruction\n");
478 adc8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
481 add8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
484 and8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
487 or8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
490 xor8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
493 sub8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
497 mov8((addr_t *)dst_addr, (addr_t *)src_addr);
501 movzx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
504 movsx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
508 not8((addr_t *)dst_addr);
511 xchg8((addr_t *)dst_addr, (addr_t *)src_addr);
516 inc8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
519 dec8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
522 neg8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
525 setb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
528 setbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
531 setl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
534 setle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
537 setnb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
540 setnbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
543 setnl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
546 setnle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
549 setno8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
552 setnp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
555 setns8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
558 setnz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
561 seto8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
564 setp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
567 sets8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
570 setz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
574 PrintError("Unknown 8 bit instruction\n");
578 } else if (src_op_size == 2) {
579 PrintDebug("Executing 16 bit instruction\n");
583 adc16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
586 add16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
589 and16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
592 or16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
595 xor16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
598 sub16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
603 inc16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
606 dec16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
609 neg16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
613 mov16((addr_t *)dst_addr, (addr_t *)src_addr);
616 movzx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
619 movsx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
622 not16((addr_t *)dst_addr);
625 xchg16((addr_t *)dst_addr, (addr_t *)src_addr);
629 PrintError("Unknown 16 bit instruction\n");
633 } else if (src_op_size == 4) {
634 PrintDebug("Executing 32 bit instruction\n");
638 adc32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
641 add32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
644 and32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
647 or32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
650 xor32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
653 sub32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
657 inc32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
660 dec32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
663 neg32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
667 mov32((addr_t *)dst_addr, (addr_t *)src_addr);
671 not32((addr_t *)dst_addr);
674 xchg32((addr_t *)dst_addr, (addr_t *)src_addr);
678 PrintError("Unknown 32 bit instruction\n");
683 } else if (src_op_size == 8) {
684 PrintDebug("Executing 64 bit instruction\n");
688 adc64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
691 add64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
694 and64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
697 or64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
700 xor64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
703 sub64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
707 inc64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
710 dec64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
713 neg64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
717 mov64((addr_t *)dst_addr, (addr_t *)src_addr);
721 not64((addr_t *)dst_addr);
724 xchg64((addr_t *)dst_addr, (addr_t *)src_addr);
728 PrintError("Unknown 64 bit instruction\n");
734 PrintError("Invalid Operation Size\n");