18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci * emulate.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2005 Keir Fraser 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Linux coding style, mod r/m decoder, segment base fixes, real-mode 108c2ecf20Sopenharmony_ci * privileged instructions: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2006 Qumranet 138c2ecf20Sopenharmony_ci * Copyright 2010 Red Hat, Inc. and/or its affiliates. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Avi Kivity <avi@qumranet.com> 168c2ecf20Sopenharmony_ci * Yaniv Kamay <yaniv@qumranet.com> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 228c2ecf20Sopenharmony_ci#include "kvm_cache_regs.h" 238c2ecf20Sopenharmony_ci#include "kvm_emulate.h" 248c2ecf20Sopenharmony_ci#include <linux/stringify.h> 258c2ecf20Sopenharmony_ci#include <asm/fpu/api.h> 268c2ecf20Sopenharmony_ci#include <asm/debugreg.h> 278c2ecf20Sopenharmony_ci#include <asm/nospec-branch.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "x86.h" 308c2ecf20Sopenharmony_ci#include "tss.h" 318c2ecf20Sopenharmony_ci#include "mmu.h" 328c2ecf20Sopenharmony_ci#include "pmu.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Operand types 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci#define OpNone 0ull 388c2ecf20Sopenharmony_ci#define OpImplicit 1ull /* No generic decode */ 398c2ecf20Sopenharmony_ci#define OpReg 2ull /* Register */ 408c2ecf20Sopenharmony_ci#define OpMem 3ull /* Memory */ 418c2ecf20Sopenharmony_ci#define OpAcc 4ull /* Accumulator: AL/AX/EAX/RAX */ 428c2ecf20Sopenharmony_ci#define OpDI 5ull /* ES:DI/EDI/RDI */ 438c2ecf20Sopenharmony_ci#define OpMem64 6ull /* Memory, 64-bit */ 448c2ecf20Sopenharmony_ci#define OpImmUByte 7ull /* Zero-extended 8-bit immediate */ 458c2ecf20Sopenharmony_ci#define OpDX 8ull /* DX register */ 468c2ecf20Sopenharmony_ci#define OpCL 9ull /* CL register (for shifts) */ 478c2ecf20Sopenharmony_ci#define OpImmByte 10ull /* 8-bit sign extended immediate */ 488c2ecf20Sopenharmony_ci#define OpOne 11ull /* Implied 1 */ 498c2ecf20Sopenharmony_ci#define OpImm 12ull /* Sign extended up to 32-bit immediate */ 508c2ecf20Sopenharmony_ci#define OpMem16 13ull /* Memory operand (16-bit). */ 518c2ecf20Sopenharmony_ci#define OpMem32 14ull /* Memory operand (32-bit). */ 528c2ecf20Sopenharmony_ci#define OpImmU 15ull /* Immediate operand, zero extended */ 538c2ecf20Sopenharmony_ci#define OpSI 16ull /* SI/ESI/RSI */ 548c2ecf20Sopenharmony_ci#define OpImmFAddr 17ull /* Immediate far address */ 558c2ecf20Sopenharmony_ci#define OpMemFAddr 18ull /* Far address in memory */ 568c2ecf20Sopenharmony_ci#define OpImmU16 19ull /* Immediate operand, 16 bits, zero extended */ 578c2ecf20Sopenharmony_ci#define OpES 20ull /* ES */ 588c2ecf20Sopenharmony_ci#define OpCS 21ull /* CS */ 598c2ecf20Sopenharmony_ci#define OpSS 22ull /* SS */ 608c2ecf20Sopenharmony_ci#define OpDS 23ull /* DS */ 618c2ecf20Sopenharmony_ci#define OpFS 24ull /* FS */ 628c2ecf20Sopenharmony_ci#define OpGS 25ull /* GS */ 638c2ecf20Sopenharmony_ci#define OpMem8 26ull /* 8-bit zero extended memory operand */ 648c2ecf20Sopenharmony_ci#define OpImm64 27ull /* Sign extended 16/32/64-bit immediate */ 658c2ecf20Sopenharmony_ci#define OpXLat 28ull /* memory at BX/EBX/RBX + zero-extended AL */ 668c2ecf20Sopenharmony_ci#define OpAccLo 29ull /* Low part of extended acc (AX/AX/EAX/RAX) */ 678c2ecf20Sopenharmony_ci#define OpAccHi 30ull /* High part of extended acc (-/DX/EDX/RDX) */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define OpBits 5 /* Width of operand field */ 708c2ecf20Sopenharmony_ci#define OpMask ((1ull << OpBits) - 1) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Opcode effective-address decode tables. 748c2ecf20Sopenharmony_ci * Note that we only emulate instructions that have at least one memory 758c2ecf20Sopenharmony_ci * operand (excluding implicit stack references). We assume that stack 768c2ecf20Sopenharmony_ci * references and instruction fetches will never occur in special memory 778c2ecf20Sopenharmony_ci * areas that require emulation. So, for example, 'mov <imm>,<reg>' need 788c2ecf20Sopenharmony_ci * not be handled. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Operand sizes: 8-bit operands or specified/overridden size. */ 828c2ecf20Sopenharmony_ci#define ByteOp (1<<0) /* 8-bit operands. */ 838c2ecf20Sopenharmony_ci/* Destination operand type. */ 848c2ecf20Sopenharmony_ci#define DstShift 1 858c2ecf20Sopenharmony_ci#define ImplicitOps (OpImplicit << DstShift) 868c2ecf20Sopenharmony_ci#define DstReg (OpReg << DstShift) 878c2ecf20Sopenharmony_ci#define DstMem (OpMem << DstShift) 888c2ecf20Sopenharmony_ci#define DstAcc (OpAcc << DstShift) 898c2ecf20Sopenharmony_ci#define DstDI (OpDI << DstShift) 908c2ecf20Sopenharmony_ci#define DstMem64 (OpMem64 << DstShift) 918c2ecf20Sopenharmony_ci#define DstMem16 (OpMem16 << DstShift) 928c2ecf20Sopenharmony_ci#define DstImmUByte (OpImmUByte << DstShift) 938c2ecf20Sopenharmony_ci#define DstDX (OpDX << DstShift) 948c2ecf20Sopenharmony_ci#define DstAccLo (OpAccLo << DstShift) 958c2ecf20Sopenharmony_ci#define DstMask (OpMask << DstShift) 968c2ecf20Sopenharmony_ci/* Source operand type. */ 978c2ecf20Sopenharmony_ci#define SrcShift 6 988c2ecf20Sopenharmony_ci#define SrcNone (OpNone << SrcShift) 998c2ecf20Sopenharmony_ci#define SrcReg (OpReg << SrcShift) 1008c2ecf20Sopenharmony_ci#define SrcMem (OpMem << SrcShift) 1018c2ecf20Sopenharmony_ci#define SrcMem16 (OpMem16 << SrcShift) 1028c2ecf20Sopenharmony_ci#define SrcMem32 (OpMem32 << SrcShift) 1038c2ecf20Sopenharmony_ci#define SrcImm (OpImm << SrcShift) 1048c2ecf20Sopenharmony_ci#define SrcImmByte (OpImmByte << SrcShift) 1058c2ecf20Sopenharmony_ci#define SrcOne (OpOne << SrcShift) 1068c2ecf20Sopenharmony_ci#define SrcImmUByte (OpImmUByte << SrcShift) 1078c2ecf20Sopenharmony_ci#define SrcImmU (OpImmU << SrcShift) 1088c2ecf20Sopenharmony_ci#define SrcSI (OpSI << SrcShift) 1098c2ecf20Sopenharmony_ci#define SrcXLat (OpXLat << SrcShift) 1108c2ecf20Sopenharmony_ci#define SrcImmFAddr (OpImmFAddr << SrcShift) 1118c2ecf20Sopenharmony_ci#define SrcMemFAddr (OpMemFAddr << SrcShift) 1128c2ecf20Sopenharmony_ci#define SrcAcc (OpAcc << SrcShift) 1138c2ecf20Sopenharmony_ci#define SrcImmU16 (OpImmU16 << SrcShift) 1148c2ecf20Sopenharmony_ci#define SrcImm64 (OpImm64 << SrcShift) 1158c2ecf20Sopenharmony_ci#define SrcDX (OpDX << SrcShift) 1168c2ecf20Sopenharmony_ci#define SrcMem8 (OpMem8 << SrcShift) 1178c2ecf20Sopenharmony_ci#define SrcAccHi (OpAccHi << SrcShift) 1188c2ecf20Sopenharmony_ci#define SrcMask (OpMask << SrcShift) 1198c2ecf20Sopenharmony_ci#define BitOp (1<<11) 1208c2ecf20Sopenharmony_ci#define MemAbs (1<<12) /* Memory operand is absolute displacement */ 1218c2ecf20Sopenharmony_ci#define String (1<<13) /* String instruction (rep capable) */ 1228c2ecf20Sopenharmony_ci#define Stack (1<<14) /* Stack instruction (push/pop) */ 1238c2ecf20Sopenharmony_ci#define GroupMask (7<<15) /* Opcode uses one of the group mechanisms */ 1248c2ecf20Sopenharmony_ci#define Group (1<<15) /* Bits 3:5 of modrm byte extend opcode */ 1258c2ecf20Sopenharmony_ci#define GroupDual (2<<15) /* Alternate decoding of mod == 3 */ 1268c2ecf20Sopenharmony_ci#define Prefix (3<<15) /* Instruction varies with 66/f2/f3 prefix */ 1278c2ecf20Sopenharmony_ci#define RMExt (4<<15) /* Opcode extension in ModRM r/m if mod == 3 */ 1288c2ecf20Sopenharmony_ci#define Escape (5<<15) /* Escape to coprocessor instruction */ 1298c2ecf20Sopenharmony_ci#define InstrDual (6<<15) /* Alternate instruction decoding of mod == 3 */ 1308c2ecf20Sopenharmony_ci#define ModeDual (7<<15) /* Different instruction for 32/64 bit */ 1318c2ecf20Sopenharmony_ci#define Sse (1<<18) /* SSE Vector instruction */ 1328c2ecf20Sopenharmony_ci/* Generic ModRM decode. */ 1338c2ecf20Sopenharmony_ci#define ModRM (1<<19) 1348c2ecf20Sopenharmony_ci/* Destination is only written; never read. */ 1358c2ecf20Sopenharmony_ci#define Mov (1<<20) 1368c2ecf20Sopenharmony_ci/* Misc flags */ 1378c2ecf20Sopenharmony_ci#define Prot (1<<21) /* instruction generates #UD if not in prot-mode */ 1388c2ecf20Sopenharmony_ci#define EmulateOnUD (1<<22) /* Emulate if unsupported by the host */ 1398c2ecf20Sopenharmony_ci#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */ 1408c2ecf20Sopenharmony_ci#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */ 1418c2ecf20Sopenharmony_ci#define Undefined (1<<25) /* No Such Instruction */ 1428c2ecf20Sopenharmony_ci#define Lock (1<<26) /* lock prefix is allowed for the instruction */ 1438c2ecf20Sopenharmony_ci#define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */ 1448c2ecf20Sopenharmony_ci#define No64 (1<<28) 1458c2ecf20Sopenharmony_ci#define PageTable (1 << 29) /* instruction used to write page table */ 1468c2ecf20Sopenharmony_ci#define NotImpl (1 << 30) /* instruction is not implemented */ 1478c2ecf20Sopenharmony_ci/* Source 2 operand type */ 1488c2ecf20Sopenharmony_ci#define Src2Shift (31) 1498c2ecf20Sopenharmony_ci#define Src2None (OpNone << Src2Shift) 1508c2ecf20Sopenharmony_ci#define Src2Mem (OpMem << Src2Shift) 1518c2ecf20Sopenharmony_ci#define Src2CL (OpCL << Src2Shift) 1528c2ecf20Sopenharmony_ci#define Src2ImmByte (OpImmByte << Src2Shift) 1538c2ecf20Sopenharmony_ci#define Src2One (OpOne << Src2Shift) 1548c2ecf20Sopenharmony_ci#define Src2Imm (OpImm << Src2Shift) 1558c2ecf20Sopenharmony_ci#define Src2ES (OpES << Src2Shift) 1568c2ecf20Sopenharmony_ci#define Src2CS (OpCS << Src2Shift) 1578c2ecf20Sopenharmony_ci#define Src2SS (OpSS << Src2Shift) 1588c2ecf20Sopenharmony_ci#define Src2DS (OpDS << Src2Shift) 1598c2ecf20Sopenharmony_ci#define Src2FS (OpFS << Src2Shift) 1608c2ecf20Sopenharmony_ci#define Src2GS (OpGS << Src2Shift) 1618c2ecf20Sopenharmony_ci#define Src2Mask (OpMask << Src2Shift) 1628c2ecf20Sopenharmony_ci#define Mmx ((u64)1 << 40) /* MMX Vector instruction */ 1638c2ecf20Sopenharmony_ci#define AlignMask ((u64)7 << 41) 1648c2ecf20Sopenharmony_ci#define Aligned ((u64)1 << 41) /* Explicitly aligned (e.g. MOVDQA) */ 1658c2ecf20Sopenharmony_ci#define Unaligned ((u64)2 << 41) /* Explicitly unaligned (e.g. MOVDQU) */ 1668c2ecf20Sopenharmony_ci#define Avx ((u64)3 << 41) /* Advanced Vector Extensions */ 1678c2ecf20Sopenharmony_ci#define Aligned16 ((u64)4 << 41) /* Aligned to 16 byte boundary (e.g. FXSAVE) */ 1688c2ecf20Sopenharmony_ci#define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */ 1698c2ecf20Sopenharmony_ci#define NoWrite ((u64)1 << 45) /* No writeback */ 1708c2ecf20Sopenharmony_ci#define SrcWrite ((u64)1 << 46) /* Write back src operand */ 1718c2ecf20Sopenharmony_ci#define NoMod ((u64)1 << 47) /* Mod field is ignored */ 1728c2ecf20Sopenharmony_ci#define Intercept ((u64)1 << 48) /* Has valid intercept field */ 1738c2ecf20Sopenharmony_ci#define CheckPerm ((u64)1 << 49) /* Has valid check_perm field */ 1748c2ecf20Sopenharmony_ci#define PrivUD ((u64)1 << 51) /* #UD instead of #GP on CPL > 0 */ 1758c2ecf20Sopenharmony_ci#define NearBranch ((u64)1 << 52) /* Near branches */ 1768c2ecf20Sopenharmony_ci#define No16 ((u64)1 << 53) /* No 16 bit operand */ 1778c2ecf20Sopenharmony_ci#define IncSP ((u64)1 << 54) /* SP is incremented before ModRM calc */ 1788c2ecf20Sopenharmony_ci#define TwoMemOp ((u64)1 << 55) /* Instruction has two memory operand */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#define DstXacc (DstAccLo | SrcAccHi | SrcWrite) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define X2(x...) x, x 1838c2ecf20Sopenharmony_ci#define X3(x...) X2(x), x 1848c2ecf20Sopenharmony_ci#define X4(x...) X2(x), X2(x) 1858c2ecf20Sopenharmony_ci#define X5(x...) X4(x), x 1868c2ecf20Sopenharmony_ci#define X6(x...) X4(x), X2(x) 1878c2ecf20Sopenharmony_ci#define X7(x...) X4(x), X3(x) 1888c2ecf20Sopenharmony_ci#define X8(x...) X4(x), X4(x) 1898c2ecf20Sopenharmony_ci#define X16(x...) X8(x), X8(x) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct opcode { 1928c2ecf20Sopenharmony_ci u64 flags : 56; 1938c2ecf20Sopenharmony_ci u64 intercept : 8; 1948c2ecf20Sopenharmony_ci union { 1958c2ecf20Sopenharmony_ci int (*execute)(struct x86_emulate_ctxt *ctxt); 1968c2ecf20Sopenharmony_ci const struct opcode *group; 1978c2ecf20Sopenharmony_ci const struct group_dual *gdual; 1988c2ecf20Sopenharmony_ci const struct gprefix *gprefix; 1998c2ecf20Sopenharmony_ci const struct escape *esc; 2008c2ecf20Sopenharmony_ci const struct instr_dual *idual; 2018c2ecf20Sopenharmony_ci const struct mode_dual *mdual; 2028c2ecf20Sopenharmony_ci void (*fastop)(struct fastop *fake); 2038c2ecf20Sopenharmony_ci } u; 2048c2ecf20Sopenharmony_ci int (*check_perm)(struct x86_emulate_ctxt *ctxt); 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistruct group_dual { 2088c2ecf20Sopenharmony_ci struct opcode mod012[8]; 2098c2ecf20Sopenharmony_ci struct opcode mod3[8]; 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistruct gprefix { 2138c2ecf20Sopenharmony_ci struct opcode pfx_no; 2148c2ecf20Sopenharmony_ci struct opcode pfx_66; 2158c2ecf20Sopenharmony_ci struct opcode pfx_f2; 2168c2ecf20Sopenharmony_ci struct opcode pfx_f3; 2178c2ecf20Sopenharmony_ci}; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistruct escape { 2208c2ecf20Sopenharmony_ci struct opcode op[8]; 2218c2ecf20Sopenharmony_ci struct opcode high[64]; 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistruct instr_dual { 2258c2ecf20Sopenharmony_ci struct opcode mod012; 2268c2ecf20Sopenharmony_ci struct opcode mod3; 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistruct mode_dual { 2308c2ecf20Sopenharmony_ci struct opcode mode32; 2318c2ecf20Sopenharmony_ci struct opcode mode64; 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define EFLG_RESERVED_ZEROS_MASK 0xffc0802a 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cienum x86_transfer_type { 2378c2ecf20Sopenharmony_ci X86_TRANSFER_NONE, 2388c2ecf20Sopenharmony_ci X86_TRANSFER_CALL_JMP, 2398c2ecf20Sopenharmony_ci X86_TRANSFER_RET, 2408c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (!(ctxt->regs_valid & (1 << nr))) { 2468c2ecf20Sopenharmony_ci ctxt->regs_valid |= 1 << nr; 2478c2ecf20Sopenharmony_ci ctxt->_regs[nr] = ctxt->ops->read_gpr(ctxt, nr); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci return ctxt->_regs[nr]; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci ctxt->regs_valid |= 1 << nr; 2558c2ecf20Sopenharmony_ci ctxt->regs_dirty |= 1 << nr; 2568c2ecf20Sopenharmony_ci return &ctxt->_regs[nr]; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic ulong *reg_rmw(struct x86_emulate_ctxt *ctxt, unsigned nr) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci reg_read(ctxt, nr); 2628c2ecf20Sopenharmony_ci return reg_write(ctxt, nr); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void writeback_registers(struct x86_emulate_ctxt *ctxt) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci unsigned reg; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci for_each_set_bit(reg, (ulong *)&ctxt->regs_dirty, 16) 2708c2ecf20Sopenharmony_ci ctxt->ops->write_gpr(ctxt, reg, ctxt->_regs[reg]); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void invalidate_registers(struct x86_emulate_ctxt *ctxt) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci ctxt->regs_dirty = 0; 2768c2ecf20Sopenharmony_ci ctxt->regs_valid = 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* 2808c2ecf20Sopenharmony_ci * These EFLAGS bits are restored from saved value during emulation, and 2818c2ecf20Sopenharmony_ci * any changes are written back to the saved value after emulation. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci#define EFLAGS_MASK (X86_EFLAGS_OF|X86_EFLAGS_SF|X86_EFLAGS_ZF|X86_EFLAGS_AF|\ 2848c2ecf20Sopenharmony_ci X86_EFLAGS_PF|X86_EFLAGS_CF) 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 2878c2ecf20Sopenharmony_ci#define ON64(x) x 2888c2ecf20Sopenharmony_ci#else 2898c2ecf20Sopenharmony_ci#define ON64(x) 2908c2ecf20Sopenharmony_ci#endif 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* 2938c2ecf20Sopenharmony_ci * fastop functions have a special calling convention: 2948c2ecf20Sopenharmony_ci * 2958c2ecf20Sopenharmony_ci * dst: rax (in/out) 2968c2ecf20Sopenharmony_ci * src: rdx (in/out) 2978c2ecf20Sopenharmony_ci * src2: rcx (in) 2988c2ecf20Sopenharmony_ci * flags: rflags (in/out) 2998c2ecf20Sopenharmony_ci * ex: rsi (in:fastop pointer, out:zero if exception) 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for 3028c2ecf20Sopenharmony_ci * different operand sizes can be reached by calculation, rather than a jump 3038c2ecf20Sopenharmony_ci * table (which would be bigger than the code). 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * The 16 byte alignment, considering 5 bytes for the RET thunk, 3 for ENDBR 3068c2ecf20Sopenharmony_ci * and 1 for the straight line speculation INT3, leaves 7 bytes for the 3078c2ecf20Sopenharmony_ci * body of the function. Currently none is larger than 4. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_cistatic int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci#define FASTOP_SIZE 16 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#define __FOP_FUNC(name) \ 3148c2ecf20Sopenharmony_ci ".align " __stringify(FASTOP_SIZE) " \n\t" \ 3158c2ecf20Sopenharmony_ci ".type " name ", @function \n\t" \ 3168c2ecf20Sopenharmony_ci name ":\n\t" 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define FOP_FUNC(name) \ 3198c2ecf20Sopenharmony_ci __FOP_FUNC(#name) 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#define __FOP_RET(name) \ 3228c2ecf20Sopenharmony_ci ASM_RET \ 3238c2ecf20Sopenharmony_ci ".size " name ", .-" name "\n\t" 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#define FOP_RET(name) \ 3268c2ecf20Sopenharmony_ci __FOP_RET(#name) 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#define __FOP_START(op, align) \ 3298c2ecf20Sopenharmony_ci extern void em_##op(struct fastop *fake); \ 3308c2ecf20Sopenharmony_ci asm(".pushsection .text, \"ax\" \n\t" \ 3318c2ecf20Sopenharmony_ci ".global em_" #op " \n\t" \ 3328c2ecf20Sopenharmony_ci ".align " __stringify(align) " \n\t" \ 3338c2ecf20Sopenharmony_ci "em_" #op ":\n\t" 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#define FOP_START(op) __FOP_START(op, FASTOP_SIZE) 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci#define FOP_END \ 3388c2ecf20Sopenharmony_ci ".popsection") 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci#define __FOPNOP(name) \ 3418c2ecf20Sopenharmony_ci __FOP_FUNC(name) \ 3428c2ecf20Sopenharmony_ci __FOP_RET(name) 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci#define FOPNOP() \ 3458c2ecf20Sopenharmony_ci __FOPNOP(__stringify(__UNIQUE_ID(nop))) 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci#define FOP1E(op, dst) \ 3488c2ecf20Sopenharmony_ci __FOP_FUNC(#op "_" #dst) \ 3498c2ecf20Sopenharmony_ci "10: " #op " %" #dst " \n\t" \ 3508c2ecf20Sopenharmony_ci __FOP_RET(#op "_" #dst) 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci#define FOP1EEX(op, dst) \ 3538c2ecf20Sopenharmony_ci FOP1E(op, dst) _ASM_EXTABLE(10b, kvm_fastop_exception) 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci#define FASTOP1(op) \ 3568c2ecf20Sopenharmony_ci FOP_START(op) \ 3578c2ecf20Sopenharmony_ci FOP1E(op##b, al) \ 3588c2ecf20Sopenharmony_ci FOP1E(op##w, ax) \ 3598c2ecf20Sopenharmony_ci FOP1E(op##l, eax) \ 3608c2ecf20Sopenharmony_ci ON64(FOP1E(op##q, rax)) \ 3618c2ecf20Sopenharmony_ci FOP_END 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/* 1-operand, using src2 (for MUL/DIV r/m) */ 3648c2ecf20Sopenharmony_ci#define FASTOP1SRC2(op, name) \ 3658c2ecf20Sopenharmony_ci FOP_START(name) \ 3668c2ecf20Sopenharmony_ci FOP1E(op, cl) \ 3678c2ecf20Sopenharmony_ci FOP1E(op, cx) \ 3688c2ecf20Sopenharmony_ci FOP1E(op, ecx) \ 3698c2ecf20Sopenharmony_ci ON64(FOP1E(op, rcx)) \ 3708c2ecf20Sopenharmony_ci FOP_END 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 1-operand, using src2 (for MUL/DIV r/m), with exceptions */ 3738c2ecf20Sopenharmony_ci#define FASTOP1SRC2EX(op, name) \ 3748c2ecf20Sopenharmony_ci FOP_START(name) \ 3758c2ecf20Sopenharmony_ci FOP1EEX(op, cl) \ 3768c2ecf20Sopenharmony_ci FOP1EEX(op, cx) \ 3778c2ecf20Sopenharmony_ci FOP1EEX(op, ecx) \ 3788c2ecf20Sopenharmony_ci ON64(FOP1EEX(op, rcx)) \ 3798c2ecf20Sopenharmony_ci FOP_END 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci#define FOP2E(op, dst, src) \ 3828c2ecf20Sopenharmony_ci __FOP_FUNC(#op "_" #dst "_" #src) \ 3838c2ecf20Sopenharmony_ci #op " %" #src ", %" #dst " \n\t" \ 3848c2ecf20Sopenharmony_ci __FOP_RET(#op "_" #dst "_" #src) 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci#define FASTOP2(op) \ 3878c2ecf20Sopenharmony_ci FOP_START(op) \ 3888c2ecf20Sopenharmony_ci FOP2E(op##b, al, dl) \ 3898c2ecf20Sopenharmony_ci FOP2E(op##w, ax, dx) \ 3908c2ecf20Sopenharmony_ci FOP2E(op##l, eax, edx) \ 3918c2ecf20Sopenharmony_ci ON64(FOP2E(op##q, rax, rdx)) \ 3928c2ecf20Sopenharmony_ci FOP_END 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* 2 operand, word only */ 3958c2ecf20Sopenharmony_ci#define FASTOP2W(op) \ 3968c2ecf20Sopenharmony_ci FOP_START(op) \ 3978c2ecf20Sopenharmony_ci FOPNOP() \ 3988c2ecf20Sopenharmony_ci FOP2E(op##w, ax, dx) \ 3998c2ecf20Sopenharmony_ci FOP2E(op##l, eax, edx) \ 4008c2ecf20Sopenharmony_ci ON64(FOP2E(op##q, rax, rdx)) \ 4018c2ecf20Sopenharmony_ci FOP_END 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* 2 operand, src is CL */ 4048c2ecf20Sopenharmony_ci#define FASTOP2CL(op) \ 4058c2ecf20Sopenharmony_ci FOP_START(op) \ 4068c2ecf20Sopenharmony_ci FOP2E(op##b, al, cl) \ 4078c2ecf20Sopenharmony_ci FOP2E(op##w, ax, cl) \ 4088c2ecf20Sopenharmony_ci FOP2E(op##l, eax, cl) \ 4098c2ecf20Sopenharmony_ci ON64(FOP2E(op##q, rax, cl)) \ 4108c2ecf20Sopenharmony_ci FOP_END 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/* 2 operand, src and dest are reversed */ 4138c2ecf20Sopenharmony_ci#define FASTOP2R(op, name) \ 4148c2ecf20Sopenharmony_ci FOP_START(name) \ 4158c2ecf20Sopenharmony_ci FOP2E(op##b, dl, al) \ 4168c2ecf20Sopenharmony_ci FOP2E(op##w, dx, ax) \ 4178c2ecf20Sopenharmony_ci FOP2E(op##l, edx, eax) \ 4188c2ecf20Sopenharmony_ci ON64(FOP2E(op##q, rdx, rax)) \ 4198c2ecf20Sopenharmony_ci FOP_END 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci#define FOP3E(op, dst, src, src2) \ 4228c2ecf20Sopenharmony_ci __FOP_FUNC(#op "_" #dst "_" #src "_" #src2) \ 4238c2ecf20Sopenharmony_ci #op " %" #src2 ", %" #src ", %" #dst " \n\t"\ 4248c2ecf20Sopenharmony_ci __FOP_RET(#op "_" #dst "_" #src "_" #src2) 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* 3-operand, word-only, src2=cl */ 4278c2ecf20Sopenharmony_ci#define FASTOP3WCL(op) \ 4288c2ecf20Sopenharmony_ci FOP_START(op) \ 4298c2ecf20Sopenharmony_ci FOPNOP() \ 4308c2ecf20Sopenharmony_ci FOP3E(op##w, ax, dx, cl) \ 4318c2ecf20Sopenharmony_ci FOP3E(op##l, eax, edx, cl) \ 4328c2ecf20Sopenharmony_ci ON64(FOP3E(op##q, rax, rdx, cl)) \ 4338c2ecf20Sopenharmony_ci FOP_END 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* Special case for SETcc - 1 instruction per cc */ 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/* 4388c2ecf20Sopenharmony_ci * Depending on .config the SETcc functions look like: 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * SETcc %al [3 bytes] 4418c2ecf20Sopenharmony_ci * RET | JMP __x86_return_thunk [1,5 bytes; CONFIG_RETHUNK] 4428c2ecf20Sopenharmony_ci * INT3 [1 byte; CONFIG_SLS] 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci#define SETCC_ALIGN 16 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci#define FOP_SETCC(op) \ 4478c2ecf20Sopenharmony_ci ".align " __stringify(SETCC_ALIGN) " \n\t" \ 4488c2ecf20Sopenharmony_ci ".type " #op ", @function \n\t" \ 4498c2ecf20Sopenharmony_ci #op ": \n\t" \ 4508c2ecf20Sopenharmony_ci #op " %al \n\t" \ 4518c2ecf20Sopenharmony_ci __FOP_RET(#op) \ 4528c2ecf20Sopenharmony_ci ".skip " __stringify(SETCC_ALIGN) " - (.-" #op "), 0xcc \n\t" 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ciasm(".pushsection .fixup, \"ax\"\n" 4558c2ecf20Sopenharmony_ci "kvm_fastop_exception: xor %esi, %esi; " ASM_RET 4568c2ecf20Sopenharmony_ci ".popsection"); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci__FOP_START(setcc, SETCC_ALIGN) 4598c2ecf20Sopenharmony_ciFOP_SETCC(seto) 4608c2ecf20Sopenharmony_ciFOP_SETCC(setno) 4618c2ecf20Sopenharmony_ciFOP_SETCC(setc) 4628c2ecf20Sopenharmony_ciFOP_SETCC(setnc) 4638c2ecf20Sopenharmony_ciFOP_SETCC(setz) 4648c2ecf20Sopenharmony_ciFOP_SETCC(setnz) 4658c2ecf20Sopenharmony_ciFOP_SETCC(setbe) 4668c2ecf20Sopenharmony_ciFOP_SETCC(setnbe) 4678c2ecf20Sopenharmony_ciFOP_SETCC(sets) 4688c2ecf20Sopenharmony_ciFOP_SETCC(setns) 4698c2ecf20Sopenharmony_ciFOP_SETCC(setp) 4708c2ecf20Sopenharmony_ciFOP_SETCC(setnp) 4718c2ecf20Sopenharmony_ciFOP_SETCC(setl) 4728c2ecf20Sopenharmony_ciFOP_SETCC(setnl) 4738c2ecf20Sopenharmony_ciFOP_SETCC(setle) 4748c2ecf20Sopenharmony_ciFOP_SETCC(setnle) 4758c2ecf20Sopenharmony_ciFOP_END; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciFOP_START(salc) 4788c2ecf20Sopenharmony_ciFOP_FUNC(salc) 4798c2ecf20Sopenharmony_ci"pushf; sbb %al, %al; popf \n\t" 4808c2ecf20Sopenharmony_ciFOP_RET(salc) 4818c2ecf20Sopenharmony_ciFOP_END; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/* 4848c2ecf20Sopenharmony_ci * XXX: inoutclob user must know where the argument is being expanded. 4858c2ecf20Sopenharmony_ci * Relying on CONFIG_CC_HAS_ASM_GOTO would allow us to remove _fault. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci#define asm_safe(insn, inoutclob...) \ 4888c2ecf20Sopenharmony_ci({ \ 4898c2ecf20Sopenharmony_ci int _fault = 0; \ 4908c2ecf20Sopenharmony_ci \ 4918c2ecf20Sopenharmony_ci asm volatile("1:" insn "\n" \ 4928c2ecf20Sopenharmony_ci "2:\n" \ 4938c2ecf20Sopenharmony_ci ".pushsection .fixup, \"ax\"\n" \ 4948c2ecf20Sopenharmony_ci "3: movl $1, %[_fault]\n" \ 4958c2ecf20Sopenharmony_ci " jmp 2b\n" \ 4968c2ecf20Sopenharmony_ci ".popsection\n" \ 4978c2ecf20Sopenharmony_ci _ASM_EXTABLE(1b, 3b) \ 4988c2ecf20Sopenharmony_ci : [_fault] "+qm"(_fault) inoutclob ); \ 4998c2ecf20Sopenharmony_ci \ 5008c2ecf20Sopenharmony_ci _fault ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; \ 5018c2ecf20Sopenharmony_ci}) 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int emulator_check_intercept(struct x86_emulate_ctxt *ctxt, 5048c2ecf20Sopenharmony_ci enum x86_intercept intercept, 5058c2ecf20Sopenharmony_ci enum x86_intercept_stage stage) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct x86_instruction_info info = { 5088c2ecf20Sopenharmony_ci .intercept = intercept, 5098c2ecf20Sopenharmony_ci .rep_prefix = ctxt->rep_prefix, 5108c2ecf20Sopenharmony_ci .modrm_mod = ctxt->modrm_mod, 5118c2ecf20Sopenharmony_ci .modrm_reg = ctxt->modrm_reg, 5128c2ecf20Sopenharmony_ci .modrm_rm = ctxt->modrm_rm, 5138c2ecf20Sopenharmony_ci .src_val = ctxt->src.val64, 5148c2ecf20Sopenharmony_ci .dst_val = ctxt->dst.val64, 5158c2ecf20Sopenharmony_ci .src_bytes = ctxt->src.bytes, 5168c2ecf20Sopenharmony_ci .dst_bytes = ctxt->dst.bytes, 5178c2ecf20Sopenharmony_ci .ad_bytes = ctxt->ad_bytes, 5188c2ecf20Sopenharmony_ci .next_rip = ctxt->eip, 5198c2ecf20Sopenharmony_ci }; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return ctxt->ops->intercept(ctxt, &info, stage); 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void assign_masked(ulong *dest, ulong src, ulong mask) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci *dest = (*dest & ~mask) | (src & mask); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic void assign_register(unsigned long *reg, u64 val, int bytes) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ 5328c2ecf20Sopenharmony_ci switch (bytes) { 5338c2ecf20Sopenharmony_ci case 1: 5348c2ecf20Sopenharmony_ci *(u8 *)reg = (u8)val; 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci case 2: 5378c2ecf20Sopenharmony_ci *(u16 *)reg = (u16)val; 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci case 4: 5408c2ecf20Sopenharmony_ci *reg = (u32)val; 5418c2ecf20Sopenharmony_ci break; /* 64b: zero-extend */ 5428c2ecf20Sopenharmony_ci case 8: 5438c2ecf20Sopenharmony_ci *reg = val; 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic inline unsigned long ad_mask(struct x86_emulate_ctxt *ctxt) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci return (1UL << (ctxt->ad_bytes << 3)) - 1; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic ulong stack_mask(struct x86_emulate_ctxt *ctxt) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci u16 sel; 5568c2ecf20Sopenharmony_ci struct desc_struct ss; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 5598c2ecf20Sopenharmony_ci return ~0UL; 5608c2ecf20Sopenharmony_ci ctxt->ops->get_segment(ctxt, &sel, &ss, NULL, VCPU_SREG_SS); 5618c2ecf20Sopenharmony_ci return ~0U >> ((ss.d ^ 1) * 16); /* d=0: 0xffff; d=1: 0xffffffff */ 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic int stack_size(struct x86_emulate_ctxt *ctxt) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci return (__fls(stack_mask(ctxt)) + 1) >> 3; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/* Access/update address held in a register, based on addressing mode. */ 5708c2ecf20Sopenharmony_cistatic inline unsigned long 5718c2ecf20Sopenharmony_ciaddress_mask(struct x86_emulate_ctxt *ctxt, unsigned long reg) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci if (ctxt->ad_bytes == sizeof(unsigned long)) 5748c2ecf20Sopenharmony_ci return reg; 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci return reg & ad_mask(ctxt); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic inline unsigned long 5808c2ecf20Sopenharmony_ciregister_address(struct x86_emulate_ctxt *ctxt, int reg) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci return address_mask(ctxt, reg_read(ctxt, reg)); 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic void masked_increment(ulong *reg, ulong mask, int inc) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci assign_masked(reg, *reg + inc, mask); 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic inline void 5918c2ecf20Sopenharmony_ciregister_address_increment(struct x86_emulate_ctxt *ctxt, int reg, int inc) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci ulong *preg = reg_rmw(ctxt, reg); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci assign_register(preg, *preg + inc, ctxt->ad_bytes); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void rsp_increment(struct x86_emulate_ctxt *ctxt, int inc) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci masked_increment(reg_rmw(ctxt, VCPU_REGS_RSP), stack_mask(ctxt), inc); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic u32 desc_limit_scaled(struct desc_struct *desc) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci u32 limit = get_desc_limit(desc); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return desc->g ? (limit << 12) | 0xfff : limit; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS) 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return ctxt->ops->get_cached_segment_base(ctxt, seg); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, 6198c2ecf20Sopenharmony_ci u32 error, bool valid) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci WARN_ON(vec > 0x1f); 6228c2ecf20Sopenharmony_ci ctxt->exception.vector = vec; 6238c2ecf20Sopenharmony_ci ctxt->exception.error_code = error; 6248c2ecf20Sopenharmony_ci ctxt->exception.error_code_valid = valid; 6258c2ecf20Sopenharmony_ci return X86EMUL_PROPAGATE_FAULT; 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_cistatic int emulate_db(struct x86_emulate_ctxt *ctxt) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci return emulate_exception(ctxt, DB_VECTOR, 0, false); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int emulate_gp(struct x86_emulate_ctxt *ctxt, int err) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci return emulate_exception(ctxt, GP_VECTOR, err, true); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int emulate_ss(struct x86_emulate_ctxt *ctxt, int err) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci return emulate_exception(ctxt, SS_VECTOR, err, true); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int emulate_ud(struct x86_emulate_ctxt *ctxt) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci return emulate_exception(ctxt, UD_VECTOR, 0, false); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int emulate_ts(struct x86_emulate_ctxt *ctxt, int err) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci return emulate_exception(ctxt, TS_VECTOR, err, true); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic int emulate_de(struct x86_emulate_ctxt *ctxt) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci return emulate_exception(ctxt, DE_VECTOR, 0, false); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int emulate_nm(struct x86_emulate_ctxt *ctxt) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci return emulate_exception(ctxt, NM_VECTOR, 0, false); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci u16 selector; 6668c2ecf20Sopenharmony_ci struct desc_struct desc; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ctxt->ops->get_segment(ctxt, &selector, &desc, NULL, seg); 6698c2ecf20Sopenharmony_ci return selector; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void set_segment_selector(struct x86_emulate_ctxt *ctxt, u16 selector, 6738c2ecf20Sopenharmony_ci unsigned seg) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci u16 dummy; 6768c2ecf20Sopenharmony_ci u32 base3; 6778c2ecf20Sopenharmony_ci struct desc_struct desc; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci ctxt->ops->get_segment(ctxt, &dummy, &desc, &base3, seg); 6808c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, base3, seg); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic inline u8 ctxt_virt_addr_bits(struct x86_emulate_ctxt *ctxt) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci return (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_LA57) ? 57 : 48; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic inline bool emul_is_noncanonical_address(u64 la, 6898c2ecf20Sopenharmony_ci struct x86_emulate_ctxt *ctxt) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci return !__is_canonical_address(la, ctxt_virt_addr_bits(ctxt)); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * x86 defines three classes of vector instructions: explicitly 6968c2ecf20Sopenharmony_ci * aligned, explicitly unaligned, and the rest, which change behaviour 6978c2ecf20Sopenharmony_ci * depending on whether they're AVX encoded or not. 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * Also included is CMPXCHG16B which is not a vector instruction, yet it is 7008c2ecf20Sopenharmony_ci * subject to the same check. FXSAVE and FXRSTOR are checked here too as their 7018c2ecf20Sopenharmony_ci * 512 bytes of data must be aligned to a 16 byte boundary. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_cistatic unsigned insn_alignment(struct x86_emulate_ctxt *ctxt, unsigned size) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci u64 alignment = ctxt->d & AlignMask; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (likely(size < 16)) 7088c2ecf20Sopenharmony_ci return 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci switch (alignment) { 7118c2ecf20Sopenharmony_ci case Unaligned: 7128c2ecf20Sopenharmony_ci case Avx: 7138c2ecf20Sopenharmony_ci return 1; 7148c2ecf20Sopenharmony_ci case Aligned16: 7158c2ecf20Sopenharmony_ci return 16; 7168c2ecf20Sopenharmony_ci case Aligned: 7178c2ecf20Sopenharmony_ci default: 7188c2ecf20Sopenharmony_ci return size; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, 7238c2ecf20Sopenharmony_ci struct segmented_address addr, 7248c2ecf20Sopenharmony_ci unsigned *max_size, unsigned size, 7258c2ecf20Sopenharmony_ci bool write, bool fetch, 7268c2ecf20Sopenharmony_ci enum x86emul_mode mode, ulong *linear) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct desc_struct desc; 7298c2ecf20Sopenharmony_ci bool usable; 7308c2ecf20Sopenharmony_ci ulong la; 7318c2ecf20Sopenharmony_ci u32 lim; 7328c2ecf20Sopenharmony_ci u16 sel; 7338c2ecf20Sopenharmony_ci u8 va_bits; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci la = seg_base(ctxt, addr.seg) + addr.ea; 7368c2ecf20Sopenharmony_ci *max_size = 0; 7378c2ecf20Sopenharmony_ci switch (mode) { 7388c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 7398c2ecf20Sopenharmony_ci *linear = la; 7408c2ecf20Sopenharmony_ci va_bits = ctxt_virt_addr_bits(ctxt); 7418c2ecf20Sopenharmony_ci if (!__is_canonical_address(la, va_bits)) 7428c2ecf20Sopenharmony_ci goto bad; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci *max_size = min_t(u64, ~0u, (1ull << va_bits) - la); 7458c2ecf20Sopenharmony_ci if (size > *max_size) 7468c2ecf20Sopenharmony_ci goto bad; 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci default: 7498c2ecf20Sopenharmony_ci *linear = la = (u32)la; 7508c2ecf20Sopenharmony_ci usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL, 7518c2ecf20Sopenharmony_ci addr.seg); 7528c2ecf20Sopenharmony_ci if (!usable) 7538c2ecf20Sopenharmony_ci goto bad; 7548c2ecf20Sopenharmony_ci /* code segment in protected mode or read-only data segment */ 7558c2ecf20Sopenharmony_ci if ((((ctxt->mode != X86EMUL_MODE_REAL) && (desc.type & 8)) 7568c2ecf20Sopenharmony_ci || !(desc.type & 2)) && write) 7578c2ecf20Sopenharmony_ci goto bad; 7588c2ecf20Sopenharmony_ci /* unreadable code segment */ 7598c2ecf20Sopenharmony_ci if (!fetch && (desc.type & 8) && !(desc.type & 2)) 7608c2ecf20Sopenharmony_ci goto bad; 7618c2ecf20Sopenharmony_ci lim = desc_limit_scaled(&desc); 7628c2ecf20Sopenharmony_ci if (!(desc.type & 8) && (desc.type & 4)) { 7638c2ecf20Sopenharmony_ci /* expand-down segment */ 7648c2ecf20Sopenharmony_ci if (addr.ea <= lim) 7658c2ecf20Sopenharmony_ci goto bad; 7668c2ecf20Sopenharmony_ci lim = desc.d ? 0xffffffff : 0xffff; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci if (addr.ea > lim) 7698c2ecf20Sopenharmony_ci goto bad; 7708c2ecf20Sopenharmony_ci if (lim == 0xffffffff) 7718c2ecf20Sopenharmony_ci *max_size = ~0u; 7728c2ecf20Sopenharmony_ci else { 7738c2ecf20Sopenharmony_ci *max_size = (u64)lim + 1 - addr.ea; 7748c2ecf20Sopenharmony_ci if (size > *max_size) 7758c2ecf20Sopenharmony_ci goto bad; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci if (la & (insn_alignment(ctxt, size) - 1)) 7808c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 7818c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 7828c2ecf20Sopenharmony_cibad: 7838c2ecf20Sopenharmony_ci if (addr.seg == VCPU_SREG_SS) 7848c2ecf20Sopenharmony_ci return emulate_ss(ctxt, 0); 7858c2ecf20Sopenharmony_ci else 7868c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int linearize(struct x86_emulate_ctxt *ctxt, 7908c2ecf20Sopenharmony_ci struct segmented_address addr, 7918c2ecf20Sopenharmony_ci unsigned size, bool write, 7928c2ecf20Sopenharmony_ci ulong *linear) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci unsigned max_size; 7958c2ecf20Sopenharmony_ci return __linearize(ctxt, addr, &max_size, size, write, false, 7968c2ecf20Sopenharmony_ci ctxt->mode, linear); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci ulong linear; 8028c2ecf20Sopenharmony_ci int rc; 8038c2ecf20Sopenharmony_ci unsigned max_size; 8048c2ecf20Sopenharmony_ci struct segmented_address addr = { .seg = VCPU_SREG_CS, 8058c2ecf20Sopenharmony_ci .ea = dst }; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (ctxt->op_bytes != sizeof(unsigned long)) 8088c2ecf20Sopenharmony_ci addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1); 8098c2ecf20Sopenharmony_ci rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear); 8108c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) 8118c2ecf20Sopenharmony_ci ctxt->_eip = addr.ea; 8128c2ecf20Sopenharmony_ci return rc; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic inline int emulator_recalc_and_set_mode(struct x86_emulate_ctxt *ctxt) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci u64 efer; 8188c2ecf20Sopenharmony_ci struct desc_struct cs; 8198c2ecf20Sopenharmony_ci u16 selector; 8208c2ecf20Sopenharmony_ci u32 base3; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (!(ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PE)) { 8258c2ecf20Sopenharmony_ci /* Real mode. cpu must not have long mode active */ 8268c2ecf20Sopenharmony_ci if (efer & EFER_LMA) 8278c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 8288c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_REAL; 8298c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (ctxt->eflags & X86_EFLAGS_VM) { 8338c2ecf20Sopenharmony_ci /* Protected/VM86 mode. cpu must not have long mode active */ 8348c2ecf20Sopenharmony_ci if (efer & EFER_LMA) 8358c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 8368c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_VM86; 8378c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci if (!ctxt->ops->get_segment(ctxt, &selector, &cs, &base3, VCPU_SREG_CS)) 8418c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (efer & EFER_LMA) { 8448c2ecf20Sopenharmony_ci if (cs.l) { 8458c2ecf20Sopenharmony_ci /* Proper long mode */ 8468c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_PROT64; 8478c2ecf20Sopenharmony_ci } else if (cs.d) { 8488c2ecf20Sopenharmony_ci /* 32 bit compatibility mode*/ 8498c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_PROT32; 8508c2ecf20Sopenharmony_ci } else { 8518c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_PROT16; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci /* Legacy 32 bit / 16 bit mode */ 8558c2ecf20Sopenharmony_ci ctxt->mode = cs.d ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic inline int assign_eip_near(struct x86_emulate_ctxt *ctxt, ulong dst) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci return assign_eip(ctxt, dst); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic int assign_eip_far(struct x86_emulate_ctxt *ctxt, ulong dst) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci int rc = emulator_recalc_and_set_mode(ctxt); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 8718c2ecf20Sopenharmony_ci return rc; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return assign_eip(ctxt, dst); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci return assign_eip_near(ctxt, ctxt->_eip + rel); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, 8828c2ecf20Sopenharmony_ci void *data, unsigned size) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int linear_write_system(struct x86_emulate_ctxt *ctxt, 8888c2ecf20Sopenharmony_ci ulong linear, void *data, 8898c2ecf20Sopenharmony_ci unsigned int size) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic int segmented_read_std(struct x86_emulate_ctxt *ctxt, 8958c2ecf20Sopenharmony_ci struct segmented_address addr, 8968c2ecf20Sopenharmony_ci void *data, 8978c2ecf20Sopenharmony_ci unsigned size) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci int rc; 9008c2ecf20Sopenharmony_ci ulong linear; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci rc = linearize(ctxt, addr, size, false, &linear); 9038c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 9048c2ecf20Sopenharmony_ci return rc; 9058c2ecf20Sopenharmony_ci return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false); 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int segmented_write_std(struct x86_emulate_ctxt *ctxt, 9098c2ecf20Sopenharmony_ci struct segmented_address addr, 9108c2ecf20Sopenharmony_ci void *data, 9118c2ecf20Sopenharmony_ci unsigned int size) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci int rc; 9148c2ecf20Sopenharmony_ci ulong linear; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci rc = linearize(ctxt, addr, size, true, &linear); 9178c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 9188c2ecf20Sopenharmony_ci return rc; 9198c2ecf20Sopenharmony_ci return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci/* 9238c2ecf20Sopenharmony_ci * Prefetch the remaining bytes of the instruction without crossing page 9248c2ecf20Sopenharmony_ci * boundary if they are not in fetch_cache yet. 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_cistatic int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci int rc; 9298c2ecf20Sopenharmony_ci unsigned size, max_size; 9308c2ecf20Sopenharmony_ci unsigned long linear; 9318c2ecf20Sopenharmony_ci int cur_size = ctxt->fetch.end - ctxt->fetch.data; 9328c2ecf20Sopenharmony_ci struct segmented_address addr = { .seg = VCPU_SREG_CS, 9338c2ecf20Sopenharmony_ci .ea = ctxt->eip + cur_size }; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* 9368c2ecf20Sopenharmony_ci * We do not know exactly how many bytes will be needed, and 9378c2ecf20Sopenharmony_ci * __linearize is expensive, so fetch as much as possible. We 9388c2ecf20Sopenharmony_ci * just have to avoid going beyond the 15 byte limit, the end 9398c2ecf20Sopenharmony_ci * of the segment, or the end of the page. 9408c2ecf20Sopenharmony_ci * 9418c2ecf20Sopenharmony_ci * __linearize is called with size 0 so that it does not do any 9428c2ecf20Sopenharmony_ci * boundary check itself. Instead, we use max_size to check 9438c2ecf20Sopenharmony_ci * against op_size. 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_ci rc = __linearize(ctxt, addr, &max_size, 0, false, true, ctxt->mode, 9468c2ecf20Sopenharmony_ci &linear); 9478c2ecf20Sopenharmony_ci if (unlikely(rc != X86EMUL_CONTINUE)) 9488c2ecf20Sopenharmony_ci return rc; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci size = min_t(unsigned, 15UL ^ cur_size, max_size); 9518c2ecf20Sopenharmony_ci size = min_t(unsigned, size, PAGE_SIZE - offset_in_page(linear)); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci * One instruction can only straddle two pages, 9558c2ecf20Sopenharmony_ci * and one has been loaded at the beginning of 9568c2ecf20Sopenharmony_ci * x86_decode_insn. So, if not enough bytes 9578c2ecf20Sopenharmony_ci * still, we must have hit the 15-byte boundary. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci if (unlikely(size < op_size)) 9608c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end, 9638c2ecf20Sopenharmony_ci size, &ctxt->exception); 9648c2ecf20Sopenharmony_ci if (unlikely(rc != X86EMUL_CONTINUE)) 9658c2ecf20Sopenharmony_ci return rc; 9668c2ecf20Sopenharmony_ci ctxt->fetch.end += size; 9678c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic __always_inline int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, 9718c2ecf20Sopenharmony_ci unsigned size) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci unsigned done_size = ctxt->fetch.end - ctxt->fetch.ptr; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (unlikely(done_size < size)) 9768c2ecf20Sopenharmony_ci return __do_insn_fetch_bytes(ctxt, size - done_size); 9778c2ecf20Sopenharmony_ci else 9788c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/* Fetch next part of the instruction being emulated. */ 9828c2ecf20Sopenharmony_ci#define insn_fetch(_type, _ctxt) \ 9838c2ecf20Sopenharmony_ci({ _type _x; \ 9848c2ecf20Sopenharmony_ci \ 9858c2ecf20Sopenharmony_ci rc = do_insn_fetch_bytes(_ctxt, sizeof(_type)); \ 9868c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) \ 9878c2ecf20Sopenharmony_ci goto done; \ 9888c2ecf20Sopenharmony_ci ctxt->_eip += sizeof(_type); \ 9898c2ecf20Sopenharmony_ci memcpy(&_x, ctxt->fetch.ptr, sizeof(_type)); \ 9908c2ecf20Sopenharmony_ci ctxt->fetch.ptr += sizeof(_type); \ 9918c2ecf20Sopenharmony_ci _x; \ 9928c2ecf20Sopenharmony_ci}) 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci#define insn_fetch_arr(_arr, _size, _ctxt) \ 9958c2ecf20Sopenharmony_ci({ \ 9968c2ecf20Sopenharmony_ci rc = do_insn_fetch_bytes(_ctxt, _size); \ 9978c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) \ 9988c2ecf20Sopenharmony_ci goto done; \ 9998c2ecf20Sopenharmony_ci ctxt->_eip += (_size); \ 10008c2ecf20Sopenharmony_ci memcpy(_arr, ctxt->fetch.ptr, _size); \ 10018c2ecf20Sopenharmony_ci ctxt->fetch.ptr += (_size); \ 10028c2ecf20Sopenharmony_ci}) 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* 10058c2ecf20Sopenharmony_ci * Given the 'reg' portion of a ModRM byte, and a register block, return a 10068c2ecf20Sopenharmony_ci * pointer into the block that addresses the relevant register. 10078c2ecf20Sopenharmony_ci * @highbyte_regs specifies whether to decode AH,CH,DH,BH. 10088c2ecf20Sopenharmony_ci */ 10098c2ecf20Sopenharmony_cistatic void *decode_register(struct x86_emulate_ctxt *ctxt, u8 modrm_reg, 10108c2ecf20Sopenharmony_ci int byteop) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci void *p; 10138c2ecf20Sopenharmony_ci int highbyte_regs = (ctxt->rex_prefix == 0) && byteop; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) 10168c2ecf20Sopenharmony_ci p = (unsigned char *)reg_rmw(ctxt, modrm_reg & 3) + 1; 10178c2ecf20Sopenharmony_ci else 10188c2ecf20Sopenharmony_ci p = reg_rmw(ctxt, modrm_reg); 10198c2ecf20Sopenharmony_ci return p; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int read_descriptor(struct x86_emulate_ctxt *ctxt, 10238c2ecf20Sopenharmony_ci struct segmented_address addr, 10248c2ecf20Sopenharmony_ci u16 *size, unsigned long *address, int op_bytes) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci int rc; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (op_bytes == 2) 10298c2ecf20Sopenharmony_ci op_bytes = 3; 10308c2ecf20Sopenharmony_ci *address = 0; 10318c2ecf20Sopenharmony_ci rc = segmented_read_std(ctxt, addr, size, 2); 10328c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 10338c2ecf20Sopenharmony_ci return rc; 10348c2ecf20Sopenharmony_ci addr.ea += 2; 10358c2ecf20Sopenharmony_ci rc = segmented_read_std(ctxt, addr, address, op_bytes); 10368c2ecf20Sopenharmony_ci return rc; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ciFASTOP2(add); 10408c2ecf20Sopenharmony_ciFASTOP2(or); 10418c2ecf20Sopenharmony_ciFASTOP2(adc); 10428c2ecf20Sopenharmony_ciFASTOP2(sbb); 10438c2ecf20Sopenharmony_ciFASTOP2(and); 10448c2ecf20Sopenharmony_ciFASTOP2(sub); 10458c2ecf20Sopenharmony_ciFASTOP2(xor); 10468c2ecf20Sopenharmony_ciFASTOP2(cmp); 10478c2ecf20Sopenharmony_ciFASTOP2(test); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ciFASTOP1SRC2(mul, mul_ex); 10508c2ecf20Sopenharmony_ciFASTOP1SRC2(imul, imul_ex); 10518c2ecf20Sopenharmony_ciFASTOP1SRC2EX(div, div_ex); 10528c2ecf20Sopenharmony_ciFASTOP1SRC2EX(idiv, idiv_ex); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ciFASTOP3WCL(shld); 10558c2ecf20Sopenharmony_ciFASTOP3WCL(shrd); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ciFASTOP2W(imul); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ciFASTOP1(not); 10608c2ecf20Sopenharmony_ciFASTOP1(neg); 10618c2ecf20Sopenharmony_ciFASTOP1(inc); 10628c2ecf20Sopenharmony_ciFASTOP1(dec); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ciFASTOP2CL(rol); 10658c2ecf20Sopenharmony_ciFASTOP2CL(ror); 10668c2ecf20Sopenharmony_ciFASTOP2CL(rcl); 10678c2ecf20Sopenharmony_ciFASTOP2CL(rcr); 10688c2ecf20Sopenharmony_ciFASTOP2CL(shl); 10698c2ecf20Sopenharmony_ciFASTOP2CL(shr); 10708c2ecf20Sopenharmony_ciFASTOP2CL(sar); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ciFASTOP2W(bsf); 10738c2ecf20Sopenharmony_ciFASTOP2W(bsr); 10748c2ecf20Sopenharmony_ciFASTOP2W(bt); 10758c2ecf20Sopenharmony_ciFASTOP2W(bts); 10768c2ecf20Sopenharmony_ciFASTOP2W(btr); 10778c2ecf20Sopenharmony_ciFASTOP2W(btc); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ciFASTOP2(xadd); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ciFASTOP2R(cmp, cmp_r); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistatic int em_bsf_c(struct x86_emulate_ctxt *ctxt) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci /* If src is zero, do not writeback, but update flags */ 10868c2ecf20Sopenharmony_ci if (ctxt->src.val == 0) 10878c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 10888c2ecf20Sopenharmony_ci return fastop(ctxt, em_bsf); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic int em_bsr_c(struct x86_emulate_ctxt *ctxt) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci /* If src is zero, do not writeback, but update flags */ 10948c2ecf20Sopenharmony_ci if (ctxt->src.val == 0) 10958c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 10968c2ecf20Sopenharmony_ci return fastop(ctxt, em_bsr); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic __always_inline u8 test_cc(unsigned int condition, unsigned long flags) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci u8 rc; 11028c2ecf20Sopenharmony_ci void (*fop)(void) = (void *)em_setcc + SETCC_ALIGN * (condition & 0xf); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci flags = (flags & EFLAGS_MASK) | X86_EFLAGS_IF; 11058c2ecf20Sopenharmony_ci asm("push %[flags]; popf; " CALL_NOSPEC 11068c2ecf20Sopenharmony_ci : "=a"(rc) : [thunk_target]"r"(fop), [flags]"r"(flags)); 11078c2ecf20Sopenharmony_ci return rc; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic void fetch_register_operand(struct operand *op) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci switch (op->bytes) { 11138c2ecf20Sopenharmony_ci case 1: 11148c2ecf20Sopenharmony_ci op->val = *(u8 *)op->addr.reg; 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci case 2: 11178c2ecf20Sopenharmony_ci op->val = *(u16 *)op->addr.reg; 11188c2ecf20Sopenharmony_ci break; 11198c2ecf20Sopenharmony_ci case 4: 11208c2ecf20Sopenharmony_ci op->val = *(u32 *)op->addr.reg; 11218c2ecf20Sopenharmony_ci break; 11228c2ecf20Sopenharmony_ci case 8: 11238c2ecf20Sopenharmony_ci op->val = *(u64 *)op->addr.reg; 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic void emulator_get_fpu(void) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci fpregs_lock(); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci fpregs_assert_state_consistent(); 11338c2ecf20Sopenharmony_ci if (test_thread_flag(TIF_NEED_FPU_LOAD)) 11348c2ecf20Sopenharmony_ci switch_fpu_return(); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic void emulator_put_fpu(void) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci fpregs_unlock(); 11408c2ecf20Sopenharmony_ci} 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_cistatic void read_sse_reg(sse128_t *data, int reg) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci emulator_get_fpu(); 11458c2ecf20Sopenharmony_ci switch (reg) { 11468c2ecf20Sopenharmony_ci case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break; 11478c2ecf20Sopenharmony_ci case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break; 11488c2ecf20Sopenharmony_ci case 2: asm("movdqa %%xmm2, %0" : "=m"(*data)); break; 11498c2ecf20Sopenharmony_ci case 3: asm("movdqa %%xmm3, %0" : "=m"(*data)); break; 11508c2ecf20Sopenharmony_ci case 4: asm("movdqa %%xmm4, %0" : "=m"(*data)); break; 11518c2ecf20Sopenharmony_ci case 5: asm("movdqa %%xmm5, %0" : "=m"(*data)); break; 11528c2ecf20Sopenharmony_ci case 6: asm("movdqa %%xmm6, %0" : "=m"(*data)); break; 11538c2ecf20Sopenharmony_ci case 7: asm("movdqa %%xmm7, %0" : "=m"(*data)); break; 11548c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 11558c2ecf20Sopenharmony_ci case 8: asm("movdqa %%xmm8, %0" : "=m"(*data)); break; 11568c2ecf20Sopenharmony_ci case 9: asm("movdqa %%xmm9, %0" : "=m"(*data)); break; 11578c2ecf20Sopenharmony_ci case 10: asm("movdqa %%xmm10, %0" : "=m"(*data)); break; 11588c2ecf20Sopenharmony_ci case 11: asm("movdqa %%xmm11, %0" : "=m"(*data)); break; 11598c2ecf20Sopenharmony_ci case 12: asm("movdqa %%xmm12, %0" : "=m"(*data)); break; 11608c2ecf20Sopenharmony_ci case 13: asm("movdqa %%xmm13, %0" : "=m"(*data)); break; 11618c2ecf20Sopenharmony_ci case 14: asm("movdqa %%xmm14, %0" : "=m"(*data)); break; 11628c2ecf20Sopenharmony_ci case 15: asm("movdqa %%xmm15, %0" : "=m"(*data)); break; 11638c2ecf20Sopenharmony_ci#endif 11648c2ecf20Sopenharmony_ci default: BUG(); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci emulator_put_fpu(); 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic void write_sse_reg(sse128_t *data, int reg) 11708c2ecf20Sopenharmony_ci{ 11718c2ecf20Sopenharmony_ci emulator_get_fpu(); 11728c2ecf20Sopenharmony_ci switch (reg) { 11738c2ecf20Sopenharmony_ci case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break; 11748c2ecf20Sopenharmony_ci case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break; 11758c2ecf20Sopenharmony_ci case 2: asm("movdqa %0, %%xmm2" : : "m"(*data)); break; 11768c2ecf20Sopenharmony_ci case 3: asm("movdqa %0, %%xmm3" : : "m"(*data)); break; 11778c2ecf20Sopenharmony_ci case 4: asm("movdqa %0, %%xmm4" : : "m"(*data)); break; 11788c2ecf20Sopenharmony_ci case 5: asm("movdqa %0, %%xmm5" : : "m"(*data)); break; 11798c2ecf20Sopenharmony_ci case 6: asm("movdqa %0, %%xmm6" : : "m"(*data)); break; 11808c2ecf20Sopenharmony_ci case 7: asm("movdqa %0, %%xmm7" : : "m"(*data)); break; 11818c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 11828c2ecf20Sopenharmony_ci case 8: asm("movdqa %0, %%xmm8" : : "m"(*data)); break; 11838c2ecf20Sopenharmony_ci case 9: asm("movdqa %0, %%xmm9" : : "m"(*data)); break; 11848c2ecf20Sopenharmony_ci case 10: asm("movdqa %0, %%xmm10" : : "m"(*data)); break; 11858c2ecf20Sopenharmony_ci case 11: asm("movdqa %0, %%xmm11" : : "m"(*data)); break; 11868c2ecf20Sopenharmony_ci case 12: asm("movdqa %0, %%xmm12" : : "m"(*data)); break; 11878c2ecf20Sopenharmony_ci case 13: asm("movdqa %0, %%xmm13" : : "m"(*data)); break; 11888c2ecf20Sopenharmony_ci case 14: asm("movdqa %0, %%xmm14" : : "m"(*data)); break; 11898c2ecf20Sopenharmony_ci case 15: asm("movdqa %0, %%xmm15" : : "m"(*data)); break; 11908c2ecf20Sopenharmony_ci#endif 11918c2ecf20Sopenharmony_ci default: BUG(); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci emulator_put_fpu(); 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic void read_mmx_reg(u64 *data, int reg) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci emulator_get_fpu(); 11998c2ecf20Sopenharmony_ci switch (reg) { 12008c2ecf20Sopenharmony_ci case 0: asm("movq %%mm0, %0" : "=m"(*data)); break; 12018c2ecf20Sopenharmony_ci case 1: asm("movq %%mm1, %0" : "=m"(*data)); break; 12028c2ecf20Sopenharmony_ci case 2: asm("movq %%mm2, %0" : "=m"(*data)); break; 12038c2ecf20Sopenharmony_ci case 3: asm("movq %%mm3, %0" : "=m"(*data)); break; 12048c2ecf20Sopenharmony_ci case 4: asm("movq %%mm4, %0" : "=m"(*data)); break; 12058c2ecf20Sopenharmony_ci case 5: asm("movq %%mm5, %0" : "=m"(*data)); break; 12068c2ecf20Sopenharmony_ci case 6: asm("movq %%mm6, %0" : "=m"(*data)); break; 12078c2ecf20Sopenharmony_ci case 7: asm("movq %%mm7, %0" : "=m"(*data)); break; 12088c2ecf20Sopenharmony_ci default: BUG(); 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci emulator_put_fpu(); 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic void write_mmx_reg(u64 *data, int reg) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci emulator_get_fpu(); 12168c2ecf20Sopenharmony_ci switch (reg) { 12178c2ecf20Sopenharmony_ci case 0: asm("movq %0, %%mm0" : : "m"(*data)); break; 12188c2ecf20Sopenharmony_ci case 1: asm("movq %0, %%mm1" : : "m"(*data)); break; 12198c2ecf20Sopenharmony_ci case 2: asm("movq %0, %%mm2" : : "m"(*data)); break; 12208c2ecf20Sopenharmony_ci case 3: asm("movq %0, %%mm3" : : "m"(*data)); break; 12218c2ecf20Sopenharmony_ci case 4: asm("movq %0, %%mm4" : : "m"(*data)); break; 12228c2ecf20Sopenharmony_ci case 5: asm("movq %0, %%mm5" : : "m"(*data)); break; 12238c2ecf20Sopenharmony_ci case 6: asm("movq %0, %%mm6" : : "m"(*data)); break; 12248c2ecf20Sopenharmony_ci case 7: asm("movq %0, %%mm7" : : "m"(*data)); break; 12258c2ecf20Sopenharmony_ci default: BUG(); 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci emulator_put_fpu(); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic int em_fninit(struct x86_emulate_ctxt *ctxt) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM)) 12338c2ecf20Sopenharmony_ci return emulate_nm(ctxt); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci emulator_get_fpu(); 12368c2ecf20Sopenharmony_ci asm volatile("fninit"); 12378c2ecf20Sopenharmony_ci emulator_put_fpu(); 12388c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic int em_fnstcw(struct x86_emulate_ctxt *ctxt) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci u16 fcw; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM)) 12468c2ecf20Sopenharmony_ci return emulate_nm(ctxt); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci emulator_get_fpu(); 12498c2ecf20Sopenharmony_ci asm volatile("fnstcw %0": "+m"(fcw)); 12508c2ecf20Sopenharmony_ci emulator_put_fpu(); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci ctxt->dst.val = fcw; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int em_fnstsw(struct x86_emulate_ctxt *ctxt) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci u16 fsw; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM)) 12628c2ecf20Sopenharmony_ci return emulate_nm(ctxt); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci emulator_get_fpu(); 12658c2ecf20Sopenharmony_ci asm volatile("fnstsw %0": "+m"(fsw)); 12668c2ecf20Sopenharmony_ci emulator_put_fpu(); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci ctxt->dst.val = fsw; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic void decode_register_operand(struct x86_emulate_ctxt *ctxt, 12748c2ecf20Sopenharmony_ci struct operand *op) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci unsigned reg = ctxt->modrm_reg; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (!(ctxt->d & ModRM)) 12798c2ecf20Sopenharmony_ci reg = (ctxt->b & 7) | ((ctxt->rex_prefix & 1) << 3); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (ctxt->d & Sse) { 12828c2ecf20Sopenharmony_ci op->type = OP_XMM; 12838c2ecf20Sopenharmony_ci op->bytes = 16; 12848c2ecf20Sopenharmony_ci op->addr.xmm = reg; 12858c2ecf20Sopenharmony_ci read_sse_reg(&op->vec_val, reg); 12868c2ecf20Sopenharmony_ci return; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci if (ctxt->d & Mmx) { 12898c2ecf20Sopenharmony_ci reg &= 7; 12908c2ecf20Sopenharmony_ci op->type = OP_MM; 12918c2ecf20Sopenharmony_ci op->bytes = 8; 12928c2ecf20Sopenharmony_ci op->addr.mm = reg; 12938c2ecf20Sopenharmony_ci return; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci op->type = OP_REG; 12978c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 12988c2ecf20Sopenharmony_ci op->addr.reg = decode_register(ctxt, reg, ctxt->d & ByteOp); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci fetch_register_operand(op); 13018c2ecf20Sopenharmony_ci op->orig_val = op->val; 13028c2ecf20Sopenharmony_ci} 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_cistatic void adjust_modrm_seg(struct x86_emulate_ctxt *ctxt, int base_reg) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci if (base_reg == VCPU_REGS_RSP || base_reg == VCPU_REGS_RBP) 13078c2ecf20Sopenharmony_ci ctxt->modrm_seg = VCPU_SREG_SS; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic int decode_modrm(struct x86_emulate_ctxt *ctxt, 13118c2ecf20Sopenharmony_ci struct operand *op) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci u8 sib; 13148c2ecf20Sopenharmony_ci int index_reg, base_reg, scale; 13158c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 13168c2ecf20Sopenharmony_ci ulong modrm_ea = 0; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci ctxt->modrm_reg = ((ctxt->rex_prefix << 1) & 8); /* REX.R */ 13198c2ecf20Sopenharmony_ci index_reg = (ctxt->rex_prefix << 2) & 8; /* REX.X */ 13208c2ecf20Sopenharmony_ci base_reg = (ctxt->rex_prefix << 3) & 8; /* REX.B */ 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci ctxt->modrm_mod = (ctxt->modrm & 0xc0) >> 6; 13238c2ecf20Sopenharmony_ci ctxt->modrm_reg |= (ctxt->modrm & 0x38) >> 3; 13248c2ecf20Sopenharmony_ci ctxt->modrm_rm = base_reg | (ctxt->modrm & 0x07); 13258c2ecf20Sopenharmony_ci ctxt->modrm_seg = VCPU_SREG_DS; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (ctxt->modrm_mod == 3 || (ctxt->d & NoMod)) { 13288c2ecf20Sopenharmony_ci op->type = OP_REG; 13298c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 13308c2ecf20Sopenharmony_ci op->addr.reg = decode_register(ctxt, ctxt->modrm_rm, 13318c2ecf20Sopenharmony_ci ctxt->d & ByteOp); 13328c2ecf20Sopenharmony_ci if (ctxt->d & Sse) { 13338c2ecf20Sopenharmony_ci op->type = OP_XMM; 13348c2ecf20Sopenharmony_ci op->bytes = 16; 13358c2ecf20Sopenharmony_ci op->addr.xmm = ctxt->modrm_rm; 13368c2ecf20Sopenharmony_ci read_sse_reg(&op->vec_val, ctxt->modrm_rm); 13378c2ecf20Sopenharmony_ci return rc; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci if (ctxt->d & Mmx) { 13408c2ecf20Sopenharmony_ci op->type = OP_MM; 13418c2ecf20Sopenharmony_ci op->bytes = 8; 13428c2ecf20Sopenharmony_ci op->addr.mm = ctxt->modrm_rm & 7; 13438c2ecf20Sopenharmony_ci return rc; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci fetch_register_operand(op); 13468c2ecf20Sopenharmony_ci return rc; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci op->type = OP_MEM; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (ctxt->ad_bytes == 2) { 13528c2ecf20Sopenharmony_ci unsigned bx = reg_read(ctxt, VCPU_REGS_RBX); 13538c2ecf20Sopenharmony_ci unsigned bp = reg_read(ctxt, VCPU_REGS_RBP); 13548c2ecf20Sopenharmony_ci unsigned si = reg_read(ctxt, VCPU_REGS_RSI); 13558c2ecf20Sopenharmony_ci unsigned di = reg_read(ctxt, VCPU_REGS_RDI); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci /* 16-bit ModR/M decode. */ 13588c2ecf20Sopenharmony_ci switch (ctxt->modrm_mod) { 13598c2ecf20Sopenharmony_ci case 0: 13608c2ecf20Sopenharmony_ci if (ctxt->modrm_rm == 6) 13618c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(u16, ctxt); 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci case 1: 13648c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(s8, ctxt); 13658c2ecf20Sopenharmony_ci break; 13668c2ecf20Sopenharmony_ci case 2: 13678c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(u16, ctxt); 13688c2ecf20Sopenharmony_ci break; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci switch (ctxt->modrm_rm) { 13718c2ecf20Sopenharmony_ci case 0: 13728c2ecf20Sopenharmony_ci modrm_ea += bx + si; 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci case 1: 13758c2ecf20Sopenharmony_ci modrm_ea += bx + di; 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci case 2: 13788c2ecf20Sopenharmony_ci modrm_ea += bp + si; 13798c2ecf20Sopenharmony_ci break; 13808c2ecf20Sopenharmony_ci case 3: 13818c2ecf20Sopenharmony_ci modrm_ea += bp + di; 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci case 4: 13848c2ecf20Sopenharmony_ci modrm_ea += si; 13858c2ecf20Sopenharmony_ci break; 13868c2ecf20Sopenharmony_ci case 5: 13878c2ecf20Sopenharmony_ci modrm_ea += di; 13888c2ecf20Sopenharmony_ci break; 13898c2ecf20Sopenharmony_ci case 6: 13908c2ecf20Sopenharmony_ci if (ctxt->modrm_mod != 0) 13918c2ecf20Sopenharmony_ci modrm_ea += bp; 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci case 7: 13948c2ecf20Sopenharmony_ci modrm_ea += bx; 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci if (ctxt->modrm_rm == 2 || ctxt->modrm_rm == 3 || 13988c2ecf20Sopenharmony_ci (ctxt->modrm_rm == 6 && ctxt->modrm_mod != 0)) 13998c2ecf20Sopenharmony_ci ctxt->modrm_seg = VCPU_SREG_SS; 14008c2ecf20Sopenharmony_ci modrm_ea = (u16)modrm_ea; 14018c2ecf20Sopenharmony_ci } else { 14028c2ecf20Sopenharmony_ci /* 32/64-bit ModR/M decode. */ 14038c2ecf20Sopenharmony_ci if ((ctxt->modrm_rm & 7) == 4) { 14048c2ecf20Sopenharmony_ci sib = insn_fetch(u8, ctxt); 14058c2ecf20Sopenharmony_ci index_reg |= (sib >> 3) & 7; 14068c2ecf20Sopenharmony_ci base_reg |= sib & 7; 14078c2ecf20Sopenharmony_ci scale = sib >> 6; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if ((base_reg & 7) == 5 && ctxt->modrm_mod == 0) 14108c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(s32, ctxt); 14118c2ecf20Sopenharmony_ci else { 14128c2ecf20Sopenharmony_ci modrm_ea += reg_read(ctxt, base_reg); 14138c2ecf20Sopenharmony_ci adjust_modrm_seg(ctxt, base_reg); 14148c2ecf20Sopenharmony_ci /* Increment ESP on POP [ESP] */ 14158c2ecf20Sopenharmony_ci if ((ctxt->d & IncSP) && 14168c2ecf20Sopenharmony_ci base_reg == VCPU_REGS_RSP) 14178c2ecf20Sopenharmony_ci modrm_ea += ctxt->op_bytes; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci if (index_reg != 4) 14208c2ecf20Sopenharmony_ci modrm_ea += reg_read(ctxt, index_reg) << scale; 14218c2ecf20Sopenharmony_ci } else if ((ctxt->modrm_rm & 7) == 5 && ctxt->modrm_mod == 0) { 14228c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(s32, ctxt); 14238c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 14248c2ecf20Sopenharmony_ci ctxt->rip_relative = 1; 14258c2ecf20Sopenharmony_ci } else { 14268c2ecf20Sopenharmony_ci base_reg = ctxt->modrm_rm; 14278c2ecf20Sopenharmony_ci modrm_ea += reg_read(ctxt, base_reg); 14288c2ecf20Sopenharmony_ci adjust_modrm_seg(ctxt, base_reg); 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci switch (ctxt->modrm_mod) { 14318c2ecf20Sopenharmony_ci case 1: 14328c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(s8, ctxt); 14338c2ecf20Sopenharmony_ci break; 14348c2ecf20Sopenharmony_ci case 2: 14358c2ecf20Sopenharmony_ci modrm_ea += insn_fetch(s32, ctxt); 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci op->addr.mem.ea = modrm_ea; 14408c2ecf20Sopenharmony_ci if (ctxt->ad_bytes != 8) 14418c2ecf20Sopenharmony_ci ctxt->memop.addr.mem.ea = (u32)ctxt->memop.addr.mem.ea; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cidone: 14448c2ecf20Sopenharmony_ci return rc; 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic int decode_abs(struct x86_emulate_ctxt *ctxt, 14488c2ecf20Sopenharmony_ci struct operand *op) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci op->type = OP_MEM; 14538c2ecf20Sopenharmony_ci switch (ctxt->ad_bytes) { 14548c2ecf20Sopenharmony_ci case 2: 14558c2ecf20Sopenharmony_ci op->addr.mem.ea = insn_fetch(u16, ctxt); 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci case 4: 14588c2ecf20Sopenharmony_ci op->addr.mem.ea = insn_fetch(u32, ctxt); 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci case 8: 14618c2ecf20Sopenharmony_ci op->addr.mem.ea = insn_fetch(u64, ctxt); 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_cidone: 14658c2ecf20Sopenharmony_ci return rc; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic void fetch_bit_operand(struct x86_emulate_ctxt *ctxt) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci long sv = 0, mask; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if (ctxt->dst.type == OP_MEM && ctxt->src.type == OP_REG) { 14738c2ecf20Sopenharmony_ci mask = ~((long)ctxt->dst.bytes * 8 - 1); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (ctxt->src.bytes == 2) 14768c2ecf20Sopenharmony_ci sv = (s16)ctxt->src.val & (s16)mask; 14778c2ecf20Sopenharmony_ci else if (ctxt->src.bytes == 4) 14788c2ecf20Sopenharmony_ci sv = (s32)ctxt->src.val & (s32)mask; 14798c2ecf20Sopenharmony_ci else 14808c2ecf20Sopenharmony_ci sv = (s64)ctxt->src.val & (s64)mask; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci ctxt->dst.addr.mem.ea = address_mask(ctxt, 14838c2ecf20Sopenharmony_ci ctxt->dst.addr.mem.ea + (sv >> 3)); 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* only subword offset */ 14878c2ecf20Sopenharmony_ci ctxt->src.val &= (ctxt->dst.bytes << 3) - 1; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic int read_emulated(struct x86_emulate_ctxt *ctxt, 14918c2ecf20Sopenharmony_ci unsigned long addr, void *dest, unsigned size) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci int rc; 14948c2ecf20Sopenharmony_ci struct read_cache *mc = &ctxt->mem_read; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (mc->pos < mc->end) 14978c2ecf20Sopenharmony_ci goto read_cached; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci WARN_ON((mc->end + size) >= sizeof(mc->data)); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size, 15028c2ecf20Sopenharmony_ci &ctxt->exception); 15038c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 15048c2ecf20Sopenharmony_ci return rc; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci mc->end += size; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ciread_cached: 15098c2ecf20Sopenharmony_ci memcpy(dest, mc->data + mc->pos, size); 15108c2ecf20Sopenharmony_ci mc->pos += size; 15118c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic int segmented_read(struct x86_emulate_ctxt *ctxt, 15158c2ecf20Sopenharmony_ci struct segmented_address addr, 15168c2ecf20Sopenharmony_ci void *data, 15178c2ecf20Sopenharmony_ci unsigned size) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci int rc; 15208c2ecf20Sopenharmony_ci ulong linear; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci rc = linearize(ctxt, addr, size, false, &linear); 15238c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 15248c2ecf20Sopenharmony_ci return rc; 15258c2ecf20Sopenharmony_ci return read_emulated(ctxt, linear, data, size); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic int segmented_write(struct x86_emulate_ctxt *ctxt, 15298c2ecf20Sopenharmony_ci struct segmented_address addr, 15308c2ecf20Sopenharmony_ci const void *data, 15318c2ecf20Sopenharmony_ci unsigned size) 15328c2ecf20Sopenharmony_ci{ 15338c2ecf20Sopenharmony_ci int rc; 15348c2ecf20Sopenharmony_ci ulong linear; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci rc = linearize(ctxt, addr, size, true, &linear); 15378c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 15388c2ecf20Sopenharmony_ci return rc; 15398c2ecf20Sopenharmony_ci return ctxt->ops->write_emulated(ctxt, linear, data, size, 15408c2ecf20Sopenharmony_ci &ctxt->exception); 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int segmented_cmpxchg(struct x86_emulate_ctxt *ctxt, 15448c2ecf20Sopenharmony_ci struct segmented_address addr, 15458c2ecf20Sopenharmony_ci const void *orig_data, const void *data, 15468c2ecf20Sopenharmony_ci unsigned size) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci int rc; 15498c2ecf20Sopenharmony_ci ulong linear; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci rc = linearize(ctxt, addr, size, true, &linear); 15528c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 15538c2ecf20Sopenharmony_ci return rc; 15548c2ecf20Sopenharmony_ci return ctxt->ops->cmpxchg_emulated(ctxt, linear, orig_data, data, 15558c2ecf20Sopenharmony_ci size, &ctxt->exception); 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic int pio_in_emulated(struct x86_emulate_ctxt *ctxt, 15598c2ecf20Sopenharmony_ci unsigned int size, unsigned short port, 15608c2ecf20Sopenharmony_ci void *dest) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci struct read_cache *rc = &ctxt->io_read; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (rc->pos == rc->end) { /* refill pio read ahead */ 15658c2ecf20Sopenharmony_ci unsigned int in_page, n; 15668c2ecf20Sopenharmony_ci unsigned int count = ctxt->rep_prefix ? 15678c2ecf20Sopenharmony_ci address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) : 1; 15688c2ecf20Sopenharmony_ci in_page = (ctxt->eflags & X86_EFLAGS_DF) ? 15698c2ecf20Sopenharmony_ci offset_in_page(reg_read(ctxt, VCPU_REGS_RDI)) : 15708c2ecf20Sopenharmony_ci PAGE_SIZE - offset_in_page(reg_read(ctxt, VCPU_REGS_RDI)); 15718c2ecf20Sopenharmony_ci n = min3(in_page, (unsigned int)sizeof(rc->data) / size, count); 15728c2ecf20Sopenharmony_ci if (n == 0) 15738c2ecf20Sopenharmony_ci n = 1; 15748c2ecf20Sopenharmony_ci rc->pos = rc->end = 0; 15758c2ecf20Sopenharmony_ci if (!ctxt->ops->pio_in_emulated(ctxt, size, port, rc->data, n)) 15768c2ecf20Sopenharmony_ci return 0; 15778c2ecf20Sopenharmony_ci rc->end = n * size; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && (ctxt->d & String) && 15818c2ecf20Sopenharmony_ci !(ctxt->eflags & X86_EFLAGS_DF)) { 15828c2ecf20Sopenharmony_ci ctxt->dst.data = rc->data + rc->pos; 15838c2ecf20Sopenharmony_ci ctxt->dst.type = OP_MEM_STR; 15848c2ecf20Sopenharmony_ci ctxt->dst.count = (rc->end - rc->pos) / size; 15858c2ecf20Sopenharmony_ci rc->pos = rc->end; 15868c2ecf20Sopenharmony_ci } else { 15878c2ecf20Sopenharmony_ci memcpy(dest, rc->data + rc->pos, size); 15888c2ecf20Sopenharmony_ci rc->pos += size; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci return 1; 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_cistatic int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, 15948c2ecf20Sopenharmony_ci u16 index, struct desc_struct *desc) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci struct desc_ptr dt; 15978c2ecf20Sopenharmony_ci ulong addr; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci ctxt->ops->get_idt(ctxt, &dt); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (dt.size < index * 8 + 7) 16028c2ecf20Sopenharmony_ci return emulate_gp(ctxt, index << 3 | 0x2); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci addr = dt.address + index * 8; 16058c2ecf20Sopenharmony_ci return linear_read_system(ctxt, addr, desc, sizeof(*desc)); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, 16098c2ecf20Sopenharmony_ci u16 selector, struct desc_ptr *dt) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 16128c2ecf20Sopenharmony_ci u32 base3 = 0; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (selector & 1 << 2) { 16158c2ecf20Sopenharmony_ci struct desc_struct desc; 16168c2ecf20Sopenharmony_ci u16 sel; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci memset(dt, 0, sizeof(*dt)); 16198c2ecf20Sopenharmony_ci if (!ops->get_segment(ctxt, &sel, &desc, &base3, 16208c2ecf20Sopenharmony_ci VCPU_SREG_LDTR)) 16218c2ecf20Sopenharmony_ci return; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */ 16248c2ecf20Sopenharmony_ci dt->address = get_desc_base(&desc) | ((u64)base3 << 32); 16258c2ecf20Sopenharmony_ci } else 16268c2ecf20Sopenharmony_ci ops->get_gdt(ctxt, dt); 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic int get_descriptor_ptr(struct x86_emulate_ctxt *ctxt, 16308c2ecf20Sopenharmony_ci u16 selector, ulong *desc_addr_p) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci struct desc_ptr dt; 16338c2ecf20Sopenharmony_ci u16 index = selector >> 3; 16348c2ecf20Sopenharmony_ci ulong addr; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci get_descriptor_table_ptr(ctxt, selector, &dt); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (dt.size < index * 8 + 7) 16398c2ecf20Sopenharmony_ci return emulate_gp(ctxt, selector & 0xfffc); 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci addr = dt.address + index * 8; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 16448c2ecf20Sopenharmony_ci if (addr >> 32 != 0) { 16458c2ecf20Sopenharmony_ci u64 efer = 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); 16488c2ecf20Sopenharmony_ci if (!(efer & EFER_LMA)) 16498c2ecf20Sopenharmony_ci addr &= (u32)-1; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci#endif 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci *desc_addr_p = addr; 16548c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci/* allowed just for 8 bytes segments */ 16588c2ecf20Sopenharmony_cistatic int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, 16598c2ecf20Sopenharmony_ci u16 selector, struct desc_struct *desc, 16608c2ecf20Sopenharmony_ci ulong *desc_addr_p) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci int rc; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci rc = get_descriptor_ptr(ctxt, selector, desc_addr_p); 16658c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 16668c2ecf20Sopenharmony_ci return rc; 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc)); 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/* allowed just for 8 bytes segments */ 16728c2ecf20Sopenharmony_cistatic int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, 16738c2ecf20Sopenharmony_ci u16 selector, struct desc_struct *desc) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci int rc; 16768c2ecf20Sopenharmony_ci ulong addr; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci rc = get_descriptor_ptr(ctxt, selector, &addr); 16798c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 16808c2ecf20Sopenharmony_ci return rc; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci return linear_write_system(ctxt, addr, desc, sizeof(*desc)); 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_cistatic int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, 16868c2ecf20Sopenharmony_ci u16 selector, int seg, u8 cpl, 16878c2ecf20Sopenharmony_ci enum x86_transfer_type transfer, 16888c2ecf20Sopenharmony_ci struct desc_struct *desc) 16898c2ecf20Sopenharmony_ci{ 16908c2ecf20Sopenharmony_ci struct desc_struct seg_desc, old_desc; 16918c2ecf20Sopenharmony_ci u8 dpl, rpl; 16928c2ecf20Sopenharmony_ci unsigned err_vec = GP_VECTOR; 16938c2ecf20Sopenharmony_ci u32 err_code = 0; 16948c2ecf20Sopenharmony_ci bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */ 16958c2ecf20Sopenharmony_ci ulong desc_addr; 16968c2ecf20Sopenharmony_ci int ret; 16978c2ecf20Sopenharmony_ci u16 dummy; 16988c2ecf20Sopenharmony_ci u32 base3 = 0; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci memset(&seg_desc, 0, sizeof(seg_desc)); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_REAL) { 17038c2ecf20Sopenharmony_ci /* set real mode segment descriptor (keep limit etc. for 17048c2ecf20Sopenharmony_ci * unreal mode) */ 17058c2ecf20Sopenharmony_ci ctxt->ops->get_segment(ctxt, &dummy, &seg_desc, NULL, seg); 17068c2ecf20Sopenharmony_ci set_desc_base(&seg_desc, selector << 4); 17078c2ecf20Sopenharmony_ci goto load; 17088c2ecf20Sopenharmony_ci } else if (seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86) { 17098c2ecf20Sopenharmony_ci /* VM86 needs a clean new segment descriptor */ 17108c2ecf20Sopenharmony_ci set_desc_base(&seg_desc, selector << 4); 17118c2ecf20Sopenharmony_ci set_desc_limit(&seg_desc, 0xffff); 17128c2ecf20Sopenharmony_ci seg_desc.type = 3; 17138c2ecf20Sopenharmony_ci seg_desc.p = 1; 17148c2ecf20Sopenharmony_ci seg_desc.s = 1; 17158c2ecf20Sopenharmony_ci seg_desc.dpl = 3; 17168c2ecf20Sopenharmony_ci goto load; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci rpl = selector & 3; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* TR should be in GDT only */ 17228c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_TR && (selector & (1 << 2))) 17238c2ecf20Sopenharmony_ci goto exception; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci /* NULL selector is not valid for TR, CS and (except for long mode) SS */ 17268c2ecf20Sopenharmony_ci if (null_selector) { 17278c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR) 17288c2ecf20Sopenharmony_ci goto exception; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_SS) { 17318c2ecf20Sopenharmony_ci if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl) 17328c2ecf20Sopenharmony_ci goto exception; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci /* 17358c2ecf20Sopenharmony_ci * ctxt->ops->set_segment expects the CPL to be in 17368c2ecf20Sopenharmony_ci * SS.DPL, so fake an expand-up 32-bit data segment. 17378c2ecf20Sopenharmony_ci */ 17388c2ecf20Sopenharmony_ci seg_desc.type = 3; 17398c2ecf20Sopenharmony_ci seg_desc.p = 1; 17408c2ecf20Sopenharmony_ci seg_desc.s = 1; 17418c2ecf20Sopenharmony_ci seg_desc.dpl = cpl; 17428c2ecf20Sopenharmony_ci seg_desc.d = 1; 17438c2ecf20Sopenharmony_ci seg_desc.g = 1; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* Skip all following checks */ 17478c2ecf20Sopenharmony_ci goto load; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr); 17518c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 17528c2ecf20Sopenharmony_ci return ret; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci err_code = selector & 0xfffc; 17558c2ecf20Sopenharmony_ci err_vec = (transfer == X86_TRANSFER_TASK_SWITCH) ? TS_VECTOR : 17568c2ecf20Sopenharmony_ci GP_VECTOR; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* can't load system descriptor into segment selector */ 17598c2ecf20Sopenharmony_ci if (seg <= VCPU_SREG_GS && !seg_desc.s) { 17608c2ecf20Sopenharmony_ci if (transfer == X86_TRANSFER_CALL_JMP) 17618c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 17628c2ecf20Sopenharmony_ci goto exception; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci dpl = seg_desc.dpl; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci switch (seg) { 17688c2ecf20Sopenharmony_ci case VCPU_SREG_SS: 17698c2ecf20Sopenharmony_ci /* 17708c2ecf20Sopenharmony_ci * segment is not a writable data segment or segment 17718c2ecf20Sopenharmony_ci * selector's RPL != CPL or segment selector's RPL != CPL 17728c2ecf20Sopenharmony_ci */ 17738c2ecf20Sopenharmony_ci if (rpl != cpl || (seg_desc.type & 0xa) != 0x2 || dpl != cpl) 17748c2ecf20Sopenharmony_ci goto exception; 17758c2ecf20Sopenharmony_ci break; 17768c2ecf20Sopenharmony_ci case VCPU_SREG_CS: 17778c2ecf20Sopenharmony_ci if (!(seg_desc.type & 8)) 17788c2ecf20Sopenharmony_ci goto exception; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (seg_desc.type & 4) { 17818c2ecf20Sopenharmony_ci /* conforming */ 17828c2ecf20Sopenharmony_ci if (dpl > cpl) 17838c2ecf20Sopenharmony_ci goto exception; 17848c2ecf20Sopenharmony_ci } else { 17858c2ecf20Sopenharmony_ci /* nonconforming */ 17868c2ecf20Sopenharmony_ci if (rpl > cpl || dpl != cpl) 17878c2ecf20Sopenharmony_ci goto exception; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci /* in long-mode d/b must be clear if l is set */ 17908c2ecf20Sopenharmony_ci if (seg_desc.d && seg_desc.l) { 17918c2ecf20Sopenharmony_ci u64 efer = 0; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); 17948c2ecf20Sopenharmony_ci if (efer & EFER_LMA) 17958c2ecf20Sopenharmony_ci goto exception; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* CS(RPL) <- CPL */ 17998c2ecf20Sopenharmony_ci selector = (selector & 0xfffc) | cpl; 18008c2ecf20Sopenharmony_ci break; 18018c2ecf20Sopenharmony_ci case VCPU_SREG_TR: 18028c2ecf20Sopenharmony_ci if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9)) 18038c2ecf20Sopenharmony_ci goto exception; 18048c2ecf20Sopenharmony_ci break; 18058c2ecf20Sopenharmony_ci case VCPU_SREG_LDTR: 18068c2ecf20Sopenharmony_ci if (seg_desc.s || seg_desc.type != 2) 18078c2ecf20Sopenharmony_ci goto exception; 18088c2ecf20Sopenharmony_ci break; 18098c2ecf20Sopenharmony_ci default: /* DS, ES, FS, or GS */ 18108c2ecf20Sopenharmony_ci /* 18118c2ecf20Sopenharmony_ci * segment is not a data or readable code segment or 18128c2ecf20Sopenharmony_ci * ((segment is a data or nonconforming code segment) 18138c2ecf20Sopenharmony_ci * and (both RPL and CPL > DPL)) 18148c2ecf20Sopenharmony_ci */ 18158c2ecf20Sopenharmony_ci if ((seg_desc.type & 0xa) == 0x8 || 18168c2ecf20Sopenharmony_ci (((seg_desc.type & 0xc) != 0xc) && 18178c2ecf20Sopenharmony_ci (rpl > dpl && cpl > dpl))) 18188c2ecf20Sopenharmony_ci goto exception; 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (!seg_desc.p) { 18238c2ecf20Sopenharmony_ci err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR; 18248c2ecf20Sopenharmony_ci goto exception; 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (seg_desc.s) { 18288c2ecf20Sopenharmony_ci /* mark segment as accessed */ 18298c2ecf20Sopenharmony_ci if (!(seg_desc.type & 1)) { 18308c2ecf20Sopenharmony_ci seg_desc.type |= 1; 18318c2ecf20Sopenharmony_ci ret = write_segment_descriptor(ctxt, selector, 18328c2ecf20Sopenharmony_ci &seg_desc); 18338c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 18348c2ecf20Sopenharmony_ci return ret; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci } else if (ctxt->mode == X86EMUL_MODE_PROT64) { 18378c2ecf20Sopenharmony_ci ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3)); 18388c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | 18418c2ecf20Sopenharmony_ci ((u64)base3 << 32), ctxt)) 18428c2ecf20Sopenharmony_ci return emulate_gp(ctxt, err_code); 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_TR) { 18468c2ecf20Sopenharmony_ci old_desc = seg_desc; 18478c2ecf20Sopenharmony_ci seg_desc.type |= 2; /* busy */ 18488c2ecf20Sopenharmony_ci ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, 18498c2ecf20Sopenharmony_ci sizeof(seg_desc), &ctxt->exception); 18508c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 18518c2ecf20Sopenharmony_ci return ret; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ciload: 18548c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg); 18558c2ecf20Sopenharmony_ci if (desc) 18568c2ecf20Sopenharmony_ci *desc = seg_desc; 18578c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 18588c2ecf20Sopenharmony_ciexception: 18598c2ecf20Sopenharmony_ci return emulate_exception(ctxt, err_vec, err_code, true); 18608c2ecf20Sopenharmony_ci} 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_cistatic int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, 18638c2ecf20Sopenharmony_ci u16 selector, int seg) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci u8 cpl = ctxt->ops->cpl(ctxt); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci /* 18688c2ecf20Sopenharmony_ci * None of MOV, POP and LSS can load a NULL selector in CPL=3, but 18698c2ecf20Sopenharmony_ci * they can load it at CPL<3 (Intel's manual says only LSS can, 18708c2ecf20Sopenharmony_ci * but it's wrong). 18718c2ecf20Sopenharmony_ci * 18728c2ecf20Sopenharmony_ci * However, the Intel manual says that putting IST=1/DPL=3 in 18738c2ecf20Sopenharmony_ci * an interrupt gate will result in SS=3 (the AMD manual instead 18748c2ecf20Sopenharmony_ci * says it doesn't), so allow SS=3 in __load_segment_descriptor 18758c2ecf20Sopenharmony_ci * and only forbid it here. 18768c2ecf20Sopenharmony_ci */ 18778c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_SS && selector == 3 && 18788c2ecf20Sopenharmony_ci ctxt->mode == X86EMUL_MODE_PROT64) 18798c2ecf20Sopenharmony_ci return emulate_exception(ctxt, GP_VECTOR, 0, true); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci return __load_segment_descriptor(ctxt, selector, seg, cpl, 18828c2ecf20Sopenharmony_ci X86_TRANSFER_NONE, NULL); 18838c2ecf20Sopenharmony_ci} 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_cistatic void write_register_operand(struct operand *op) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci return assign_register(op->addr.reg, op->val, op->bytes); 18888c2ecf20Sopenharmony_ci} 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_cistatic int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op) 18918c2ecf20Sopenharmony_ci{ 18928c2ecf20Sopenharmony_ci switch (op->type) { 18938c2ecf20Sopenharmony_ci case OP_REG: 18948c2ecf20Sopenharmony_ci write_register_operand(op); 18958c2ecf20Sopenharmony_ci break; 18968c2ecf20Sopenharmony_ci case OP_MEM: 18978c2ecf20Sopenharmony_ci if (ctxt->lock_prefix) 18988c2ecf20Sopenharmony_ci return segmented_cmpxchg(ctxt, 18998c2ecf20Sopenharmony_ci op->addr.mem, 19008c2ecf20Sopenharmony_ci &op->orig_val, 19018c2ecf20Sopenharmony_ci &op->val, 19028c2ecf20Sopenharmony_ci op->bytes); 19038c2ecf20Sopenharmony_ci else 19048c2ecf20Sopenharmony_ci return segmented_write(ctxt, 19058c2ecf20Sopenharmony_ci op->addr.mem, 19068c2ecf20Sopenharmony_ci &op->val, 19078c2ecf20Sopenharmony_ci op->bytes); 19088c2ecf20Sopenharmony_ci break; 19098c2ecf20Sopenharmony_ci case OP_MEM_STR: 19108c2ecf20Sopenharmony_ci return segmented_write(ctxt, 19118c2ecf20Sopenharmony_ci op->addr.mem, 19128c2ecf20Sopenharmony_ci op->data, 19138c2ecf20Sopenharmony_ci op->bytes * op->count); 19148c2ecf20Sopenharmony_ci break; 19158c2ecf20Sopenharmony_ci case OP_XMM: 19168c2ecf20Sopenharmony_ci write_sse_reg(&op->vec_val, op->addr.xmm); 19178c2ecf20Sopenharmony_ci break; 19188c2ecf20Sopenharmony_ci case OP_MM: 19198c2ecf20Sopenharmony_ci write_mmx_reg(&op->mm_val, op->addr.mm); 19208c2ecf20Sopenharmony_ci break; 19218c2ecf20Sopenharmony_ci case OP_NONE: 19228c2ecf20Sopenharmony_ci /* no writeback */ 19238c2ecf20Sopenharmony_ci break; 19248c2ecf20Sopenharmony_ci default: 19258c2ecf20Sopenharmony_ci break; 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 19288c2ecf20Sopenharmony_ci} 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_cistatic int push(struct x86_emulate_ctxt *ctxt, void *data, int bytes) 19318c2ecf20Sopenharmony_ci{ 19328c2ecf20Sopenharmony_ci struct segmented_address addr; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci rsp_increment(ctxt, -bytes); 19358c2ecf20Sopenharmony_ci addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt); 19368c2ecf20Sopenharmony_ci addr.seg = VCPU_SREG_SS; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci return segmented_write(ctxt, addr, data, bytes); 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic int em_push(struct x86_emulate_ctxt *ctxt) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci /* Disable writeback. */ 19448c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 19458c2ecf20Sopenharmony_ci return push(ctxt, &ctxt->src.val, ctxt->op_bytes); 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_cistatic int emulate_pop(struct x86_emulate_ctxt *ctxt, 19498c2ecf20Sopenharmony_ci void *dest, int len) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int rc; 19528c2ecf20Sopenharmony_ci struct segmented_address addr; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt); 19558c2ecf20Sopenharmony_ci addr.seg = VCPU_SREG_SS; 19568c2ecf20Sopenharmony_ci rc = segmented_read(ctxt, addr, dest, len); 19578c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 19588c2ecf20Sopenharmony_ci return rc; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci rsp_increment(ctxt, len); 19618c2ecf20Sopenharmony_ci return rc; 19628c2ecf20Sopenharmony_ci} 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_cistatic int em_pop(struct x86_emulate_ctxt *ctxt) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci return emulate_pop(ctxt, &ctxt->dst.val, ctxt->op_bytes); 19678c2ecf20Sopenharmony_ci} 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic int emulate_popf(struct x86_emulate_ctxt *ctxt, 19708c2ecf20Sopenharmony_ci void *dest, int len) 19718c2ecf20Sopenharmony_ci{ 19728c2ecf20Sopenharmony_ci int rc; 19738c2ecf20Sopenharmony_ci unsigned long val, change_mask; 19748c2ecf20Sopenharmony_ci int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> X86_EFLAGS_IOPL_BIT; 19758c2ecf20Sopenharmony_ci int cpl = ctxt->ops->cpl(ctxt); 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &val, len); 19788c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 19798c2ecf20Sopenharmony_ci return rc; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci change_mask = X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | 19828c2ecf20Sopenharmony_ci X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF | 19838c2ecf20Sopenharmony_ci X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_NT | 19848c2ecf20Sopenharmony_ci X86_EFLAGS_AC | X86_EFLAGS_ID; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci switch(ctxt->mode) { 19878c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 19888c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT32: 19898c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT16: 19908c2ecf20Sopenharmony_ci if (cpl == 0) 19918c2ecf20Sopenharmony_ci change_mask |= X86_EFLAGS_IOPL; 19928c2ecf20Sopenharmony_ci if (cpl <= iopl) 19938c2ecf20Sopenharmony_ci change_mask |= X86_EFLAGS_IF; 19948c2ecf20Sopenharmony_ci break; 19958c2ecf20Sopenharmony_ci case X86EMUL_MODE_VM86: 19968c2ecf20Sopenharmony_ci if (iopl < 3) 19978c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 19988c2ecf20Sopenharmony_ci change_mask |= X86_EFLAGS_IF; 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci default: /* real mode */ 20018c2ecf20Sopenharmony_ci change_mask |= (X86_EFLAGS_IOPL | X86_EFLAGS_IF); 20028c2ecf20Sopenharmony_ci break; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci *(unsigned long *)dest = 20068c2ecf20Sopenharmony_ci (ctxt->eflags & ~change_mask) | (val & change_mask); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci return rc; 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic int em_popf(struct x86_emulate_ctxt *ctxt) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci ctxt->dst.type = OP_REG; 20148c2ecf20Sopenharmony_ci ctxt->dst.addr.reg = &ctxt->eflags; 20158c2ecf20Sopenharmony_ci ctxt->dst.bytes = ctxt->op_bytes; 20168c2ecf20Sopenharmony_ci return emulate_popf(ctxt, &ctxt->dst.val, ctxt->op_bytes); 20178c2ecf20Sopenharmony_ci} 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_cistatic int em_enter(struct x86_emulate_ctxt *ctxt) 20208c2ecf20Sopenharmony_ci{ 20218c2ecf20Sopenharmony_ci int rc; 20228c2ecf20Sopenharmony_ci unsigned frame_size = ctxt->src.val; 20238c2ecf20Sopenharmony_ci unsigned nesting_level = ctxt->src2.val & 31; 20248c2ecf20Sopenharmony_ci ulong rbp; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci if (nesting_level) 20278c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci rbp = reg_read(ctxt, VCPU_REGS_RBP); 20308c2ecf20Sopenharmony_ci rc = push(ctxt, &rbp, stack_size(ctxt)); 20318c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 20328c2ecf20Sopenharmony_ci return rc; 20338c2ecf20Sopenharmony_ci assign_masked(reg_rmw(ctxt, VCPU_REGS_RBP), reg_read(ctxt, VCPU_REGS_RSP), 20348c2ecf20Sopenharmony_ci stack_mask(ctxt)); 20358c2ecf20Sopenharmony_ci assign_masked(reg_rmw(ctxt, VCPU_REGS_RSP), 20368c2ecf20Sopenharmony_ci reg_read(ctxt, VCPU_REGS_RSP) - frame_size, 20378c2ecf20Sopenharmony_ci stack_mask(ctxt)); 20388c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 20398c2ecf20Sopenharmony_ci} 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_cistatic int em_leave(struct x86_emulate_ctxt *ctxt) 20428c2ecf20Sopenharmony_ci{ 20438c2ecf20Sopenharmony_ci assign_masked(reg_rmw(ctxt, VCPU_REGS_RSP), reg_read(ctxt, VCPU_REGS_RBP), 20448c2ecf20Sopenharmony_ci stack_mask(ctxt)); 20458c2ecf20Sopenharmony_ci return emulate_pop(ctxt, reg_rmw(ctxt, VCPU_REGS_RBP), ctxt->op_bytes); 20468c2ecf20Sopenharmony_ci} 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_cistatic int em_push_sreg(struct x86_emulate_ctxt *ctxt) 20498c2ecf20Sopenharmony_ci{ 20508c2ecf20Sopenharmony_ci int seg = ctxt->src2.val; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci ctxt->src.val = get_segment_selector(ctxt, seg); 20538c2ecf20Sopenharmony_ci if (ctxt->op_bytes == 4) { 20548c2ecf20Sopenharmony_ci rsp_increment(ctxt, -2); 20558c2ecf20Sopenharmony_ci ctxt->op_bytes = 2; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci return em_push(ctxt); 20598c2ecf20Sopenharmony_ci} 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_cistatic int em_pop_sreg(struct x86_emulate_ctxt *ctxt) 20628c2ecf20Sopenharmony_ci{ 20638c2ecf20Sopenharmony_ci int seg = ctxt->src2.val; 20648c2ecf20Sopenharmony_ci unsigned long selector; 20658c2ecf20Sopenharmony_ci int rc; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &selector, 2); 20688c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 20698c2ecf20Sopenharmony_ci return rc; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (seg == VCPU_SREG_SS) 20728c2ecf20Sopenharmony_ci ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS; 20738c2ecf20Sopenharmony_ci if (ctxt->op_bytes > 2) 20748c2ecf20Sopenharmony_ci rsp_increment(ctxt, ctxt->op_bytes - 2); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci rc = load_segment_descriptor(ctxt, (u16)selector, seg); 20778c2ecf20Sopenharmony_ci return rc; 20788c2ecf20Sopenharmony_ci} 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_cistatic int em_pusha(struct x86_emulate_ctxt *ctxt) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci unsigned long old_esp = reg_read(ctxt, VCPU_REGS_RSP); 20838c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 20848c2ecf20Sopenharmony_ci int reg = VCPU_REGS_RAX; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci while (reg <= VCPU_REGS_RDI) { 20878c2ecf20Sopenharmony_ci (reg == VCPU_REGS_RSP) ? 20888c2ecf20Sopenharmony_ci (ctxt->src.val = old_esp) : (ctxt->src.val = reg_read(ctxt, reg)); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci rc = em_push(ctxt); 20918c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 20928c2ecf20Sopenharmony_ci return rc; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci ++reg; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci return rc; 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_cistatic int em_pushf(struct x86_emulate_ctxt *ctxt) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci ctxt->src.val = (unsigned long)ctxt->eflags & ~X86_EFLAGS_VM; 21038c2ecf20Sopenharmony_ci return em_push(ctxt); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic int em_popa(struct x86_emulate_ctxt *ctxt) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 21098c2ecf20Sopenharmony_ci int reg = VCPU_REGS_RDI; 21108c2ecf20Sopenharmony_ci u32 val; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci while (reg >= VCPU_REGS_RAX) { 21138c2ecf20Sopenharmony_ci if (reg == VCPU_REGS_RSP) { 21148c2ecf20Sopenharmony_ci rsp_increment(ctxt, ctxt->op_bytes); 21158c2ecf20Sopenharmony_ci --reg; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &val, ctxt->op_bytes); 21198c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21208c2ecf20Sopenharmony_ci break; 21218c2ecf20Sopenharmony_ci assign_register(reg_rmw(ctxt, reg), val, ctxt->op_bytes); 21228c2ecf20Sopenharmony_ci --reg; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci return rc; 21258c2ecf20Sopenharmony_ci} 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_cistatic int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 21308c2ecf20Sopenharmony_ci int rc; 21318c2ecf20Sopenharmony_ci struct desc_ptr dt; 21328c2ecf20Sopenharmony_ci gva_t cs_addr; 21338c2ecf20Sopenharmony_ci gva_t eip_addr; 21348c2ecf20Sopenharmony_ci u16 cs, eip; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* TODO: Add limit checks */ 21378c2ecf20Sopenharmony_ci ctxt->src.val = ctxt->eflags; 21388c2ecf20Sopenharmony_ci rc = em_push(ctxt); 21398c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21408c2ecf20Sopenharmony_ci return rc; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci ctxt->eflags &= ~(X86_EFLAGS_IF | X86_EFLAGS_TF | X86_EFLAGS_AC); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci ctxt->src.val = get_segment_selector(ctxt, VCPU_SREG_CS); 21458c2ecf20Sopenharmony_ci rc = em_push(ctxt); 21468c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21478c2ecf20Sopenharmony_ci return rc; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci ctxt->src.val = ctxt->_eip; 21508c2ecf20Sopenharmony_ci rc = em_push(ctxt); 21518c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21528c2ecf20Sopenharmony_ci return rc; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci ops->get_idt(ctxt, &dt); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci eip_addr = dt.address + (irq << 2); 21578c2ecf20Sopenharmony_ci cs_addr = dt.address + (irq << 2) + 2; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci rc = linear_read_system(ctxt, cs_addr, &cs, 2); 21608c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21618c2ecf20Sopenharmony_ci return rc; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci rc = linear_read_system(ctxt, eip_addr, &eip, 2); 21648c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21658c2ecf20Sopenharmony_ci return rc; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci rc = load_segment_descriptor(ctxt, cs, VCPU_SREG_CS); 21688c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 21698c2ecf20Sopenharmony_ci return rc; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci ctxt->_eip = eip; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci return rc; 21748c2ecf20Sopenharmony_ci} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ciint emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci int rc; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci invalidate_registers(ctxt); 21818c2ecf20Sopenharmony_ci rc = __emulate_int_real(ctxt, irq); 21828c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) 21838c2ecf20Sopenharmony_ci writeback_registers(ctxt); 21848c2ecf20Sopenharmony_ci return rc; 21858c2ecf20Sopenharmony_ci} 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_cistatic int emulate_int(struct x86_emulate_ctxt *ctxt, int irq) 21888c2ecf20Sopenharmony_ci{ 21898c2ecf20Sopenharmony_ci switch(ctxt->mode) { 21908c2ecf20Sopenharmony_ci case X86EMUL_MODE_REAL: 21918c2ecf20Sopenharmony_ci return __emulate_int_real(ctxt, irq); 21928c2ecf20Sopenharmony_ci case X86EMUL_MODE_VM86: 21938c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT16: 21948c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT32: 21958c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 21968c2ecf20Sopenharmony_ci default: 21978c2ecf20Sopenharmony_ci /* Protected mode interrupts unimplemented yet */ 21988c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci} 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic int emulate_iret_real(struct x86_emulate_ctxt *ctxt) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 22058c2ecf20Sopenharmony_ci unsigned long temp_eip = 0; 22068c2ecf20Sopenharmony_ci unsigned long temp_eflags = 0; 22078c2ecf20Sopenharmony_ci unsigned long cs = 0; 22088c2ecf20Sopenharmony_ci unsigned long mask = X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | 22098c2ecf20Sopenharmony_ci X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_TF | 22108c2ecf20Sopenharmony_ci X86_EFLAGS_IF | X86_EFLAGS_DF | X86_EFLAGS_OF | 22118c2ecf20Sopenharmony_ci X86_EFLAGS_IOPL | X86_EFLAGS_NT | X86_EFLAGS_RF | 22128c2ecf20Sopenharmony_ci X86_EFLAGS_AC | X86_EFLAGS_ID | 22138c2ecf20Sopenharmony_ci X86_EFLAGS_FIXED; 22148c2ecf20Sopenharmony_ci unsigned long vm86_mask = X86_EFLAGS_VM | X86_EFLAGS_VIF | 22158c2ecf20Sopenharmony_ci X86_EFLAGS_VIP; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci /* TODO: Add stack limit check */ 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &temp_eip, ctxt->op_bytes); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22228c2ecf20Sopenharmony_ci return rc; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci if (temp_eip & ~0xffff) 22258c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &cs, ctxt->op_bytes); 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22308c2ecf20Sopenharmony_ci return rc; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &temp_eflags, ctxt->op_bytes); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22358c2ecf20Sopenharmony_ci return rc; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci rc = load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22408c2ecf20Sopenharmony_ci return rc; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci ctxt->_eip = temp_eip; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci if (ctxt->op_bytes == 4) 22458c2ecf20Sopenharmony_ci ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask)); 22468c2ecf20Sopenharmony_ci else if (ctxt->op_bytes == 2) { 22478c2ecf20Sopenharmony_ci ctxt->eflags &= ~0xffff; 22488c2ecf20Sopenharmony_ci ctxt->eflags |= temp_eflags; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */ 22528c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_FIXED; 22538c2ecf20Sopenharmony_ci ctxt->ops->set_nmi_mask(ctxt, false); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci return rc; 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic int em_iret(struct x86_emulate_ctxt *ctxt) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci switch(ctxt->mode) { 22618c2ecf20Sopenharmony_ci case X86EMUL_MODE_REAL: 22628c2ecf20Sopenharmony_ci return emulate_iret_real(ctxt); 22638c2ecf20Sopenharmony_ci case X86EMUL_MODE_VM86: 22648c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT16: 22658c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT32: 22668c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 22678c2ecf20Sopenharmony_ci default: 22688c2ecf20Sopenharmony_ci /* iret from protected mode unimplemented yet */ 22698c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_cistatic int em_jmp_far(struct x86_emulate_ctxt *ctxt) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci int rc; 22768c2ecf20Sopenharmony_ci unsigned short sel; 22778c2ecf20Sopenharmony_ci struct desc_struct new_desc; 22788c2ecf20Sopenharmony_ci u8 cpl = ctxt->ops->cpl(ctxt); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl, 22838c2ecf20Sopenharmony_ci X86_TRANSFER_CALL_JMP, 22848c2ecf20Sopenharmony_ci &new_desc); 22858c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22868c2ecf20Sopenharmony_ci return rc; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci rc = assign_eip_far(ctxt, ctxt->src.val); 22898c2ecf20Sopenharmony_ci /* Error handling is not implemented. */ 22908c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 22918c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci return rc; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_cistatic int em_jmp_abs(struct x86_emulate_ctxt *ctxt) 22978c2ecf20Sopenharmony_ci{ 22988c2ecf20Sopenharmony_ci return assign_eip_near(ctxt, ctxt->src.val); 22998c2ecf20Sopenharmony_ci} 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cistatic int em_call_near_abs(struct x86_emulate_ctxt *ctxt) 23028c2ecf20Sopenharmony_ci{ 23038c2ecf20Sopenharmony_ci int rc; 23048c2ecf20Sopenharmony_ci long int old_eip; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci old_eip = ctxt->_eip; 23078c2ecf20Sopenharmony_ci rc = assign_eip_near(ctxt, ctxt->src.val); 23088c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23098c2ecf20Sopenharmony_ci return rc; 23108c2ecf20Sopenharmony_ci ctxt->src.val = old_eip; 23118c2ecf20Sopenharmony_ci rc = em_push(ctxt); 23128c2ecf20Sopenharmony_ci return rc; 23138c2ecf20Sopenharmony_ci} 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_cistatic int em_cmpxchg8b(struct x86_emulate_ctxt *ctxt) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci u64 old = ctxt->dst.orig_val64; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci if (ctxt->dst.bytes == 16) 23208c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci if (((u32) (old >> 0) != (u32) reg_read(ctxt, VCPU_REGS_RAX)) || 23238c2ecf20Sopenharmony_ci ((u32) (old >> 32) != (u32) reg_read(ctxt, VCPU_REGS_RDX))) { 23248c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = (u32) (old >> 0); 23258c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = (u32) (old >> 32); 23268c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_ZF; 23278c2ecf20Sopenharmony_ci } else { 23288c2ecf20Sopenharmony_ci ctxt->dst.val64 = ((u64)reg_read(ctxt, VCPU_REGS_RCX) << 32) | 23298c2ecf20Sopenharmony_ci (u32) reg_read(ctxt, VCPU_REGS_RBX); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_ZF; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 23348c2ecf20Sopenharmony_ci} 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_cistatic int em_ret(struct x86_emulate_ctxt *ctxt) 23378c2ecf20Sopenharmony_ci{ 23388c2ecf20Sopenharmony_ci int rc; 23398c2ecf20Sopenharmony_ci unsigned long eip; 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); 23428c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23438c2ecf20Sopenharmony_ci return rc; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci return assign_eip_near(ctxt, eip); 23468c2ecf20Sopenharmony_ci} 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_cistatic int em_ret_far(struct x86_emulate_ctxt *ctxt) 23498c2ecf20Sopenharmony_ci{ 23508c2ecf20Sopenharmony_ci int rc; 23518c2ecf20Sopenharmony_ci unsigned long eip, cs; 23528c2ecf20Sopenharmony_ci int cpl = ctxt->ops->cpl(ctxt); 23538c2ecf20Sopenharmony_ci struct desc_struct new_desc; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); 23568c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23578c2ecf20Sopenharmony_ci return rc; 23588c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &cs, ctxt->op_bytes); 23598c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23608c2ecf20Sopenharmony_ci return rc; 23618c2ecf20Sopenharmony_ci /* Outer-privilege level return is not implemented */ 23628c2ecf20Sopenharmony_ci if (ctxt->mode >= X86EMUL_MODE_PROT16 && (cs & 3) > cpl) 23638c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 23648c2ecf20Sopenharmony_ci rc = __load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS, cpl, 23658c2ecf20Sopenharmony_ci X86_TRANSFER_RET, 23668c2ecf20Sopenharmony_ci &new_desc); 23678c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23688c2ecf20Sopenharmony_ci return rc; 23698c2ecf20Sopenharmony_ci rc = assign_eip_far(ctxt, eip); 23708c2ecf20Sopenharmony_ci /* Error handling is not implemented. */ 23718c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23728c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci return rc; 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic int em_ret_far_imm(struct x86_emulate_ctxt *ctxt) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci int rc; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci rc = em_ret_far(ctxt); 23828c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 23838c2ecf20Sopenharmony_ci return rc; 23848c2ecf20Sopenharmony_ci rsp_increment(ctxt, ctxt->src.val); 23858c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_cistatic int em_cmpxchg(struct x86_emulate_ctxt *ctxt) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci /* Save real source value, then compare EAX against destination. */ 23918c2ecf20Sopenharmony_ci ctxt->dst.orig_val = ctxt->dst.val; 23928c2ecf20Sopenharmony_ci ctxt->dst.val = reg_read(ctxt, VCPU_REGS_RAX); 23938c2ecf20Sopenharmony_ci ctxt->src.orig_val = ctxt->src.val; 23948c2ecf20Sopenharmony_ci ctxt->src.val = ctxt->dst.orig_val; 23958c2ecf20Sopenharmony_ci fastop(ctxt, em_cmp); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (ctxt->eflags & X86_EFLAGS_ZF) { 23988c2ecf20Sopenharmony_ci /* Success: write back to memory; no update of EAX */ 23998c2ecf20Sopenharmony_ci ctxt->src.type = OP_NONE; 24008c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src.orig_val; 24018c2ecf20Sopenharmony_ci } else { 24028c2ecf20Sopenharmony_ci /* Failure: write the value we saw to EAX. */ 24038c2ecf20Sopenharmony_ci ctxt->src.type = OP_REG; 24048c2ecf20Sopenharmony_ci ctxt->src.addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX); 24058c2ecf20Sopenharmony_ci ctxt->src.val = ctxt->dst.orig_val; 24068c2ecf20Sopenharmony_ci /* Create write-cycle to dest by writing the same value */ 24078c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->dst.orig_val; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 24108c2ecf20Sopenharmony_ci} 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_cistatic int em_lseg(struct x86_emulate_ctxt *ctxt) 24138c2ecf20Sopenharmony_ci{ 24148c2ecf20Sopenharmony_ci int seg = ctxt->src2.val; 24158c2ecf20Sopenharmony_ci unsigned short sel; 24168c2ecf20Sopenharmony_ci int rc; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci rc = load_segment_descriptor(ctxt, sel, seg); 24218c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 24228c2ecf20Sopenharmony_ci return rc; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src.val; 24258c2ecf20Sopenharmony_ci return rc; 24268c2ecf20Sopenharmony_ci} 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_cistatic int emulator_has_longmode(struct x86_emulate_ctxt *ctxt) 24298c2ecf20Sopenharmony_ci{ 24308c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 24318c2ecf20Sopenharmony_ci return ctxt->ops->guest_has_long_mode(ctxt); 24328c2ecf20Sopenharmony_ci#else 24338c2ecf20Sopenharmony_ci return false; 24348c2ecf20Sopenharmony_ci#endif 24358c2ecf20Sopenharmony_ci} 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cistatic void rsm_set_desc_flags(struct desc_struct *desc, u32 flags) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci desc->g = (flags >> 23) & 1; 24408c2ecf20Sopenharmony_ci desc->d = (flags >> 22) & 1; 24418c2ecf20Sopenharmony_ci desc->l = (flags >> 21) & 1; 24428c2ecf20Sopenharmony_ci desc->avl = (flags >> 20) & 1; 24438c2ecf20Sopenharmony_ci desc->p = (flags >> 15) & 1; 24448c2ecf20Sopenharmony_ci desc->dpl = (flags >> 13) & 3; 24458c2ecf20Sopenharmony_ci desc->s = (flags >> 12) & 1; 24468c2ecf20Sopenharmony_ci desc->type = (flags >> 8) & 15; 24478c2ecf20Sopenharmony_ci} 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistatic int rsm_load_seg_32(struct x86_emulate_ctxt *ctxt, const char *smstate, 24508c2ecf20Sopenharmony_ci int n) 24518c2ecf20Sopenharmony_ci{ 24528c2ecf20Sopenharmony_ci struct desc_struct desc; 24538c2ecf20Sopenharmony_ci int offset; 24548c2ecf20Sopenharmony_ci u16 selector; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u32, smstate, 0x7fa8 + n * 4); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci if (n < 3) 24598c2ecf20Sopenharmony_ci offset = 0x7f84 + n * 12; 24608c2ecf20Sopenharmony_ci else 24618c2ecf20Sopenharmony_ci offset = 0x7f2c + (n - 3) * 12; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, offset + 8)); 24648c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, offset + 4)); 24658c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smstate, offset)); 24668c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, 0, n); 24678c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 24718c2ecf20Sopenharmony_cistatic int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, const char *smstate, 24728c2ecf20Sopenharmony_ci int n) 24738c2ecf20Sopenharmony_ci{ 24748c2ecf20Sopenharmony_ci struct desc_struct desc; 24758c2ecf20Sopenharmony_ci int offset; 24768c2ecf20Sopenharmony_ci u16 selector; 24778c2ecf20Sopenharmony_ci u32 base3; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci offset = 0x7e00 + n * 16; 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u16, smstate, offset); 24828c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u16, smstate, offset + 2) << 8); 24838c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, offset + 4)); 24848c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, offset + 8)); 24858c2ecf20Sopenharmony_ci base3 = GET_SMSTATE(u32, smstate, offset + 12); 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, base3, n); 24888c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci#endif 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_cistatic int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt, 24938c2ecf20Sopenharmony_ci u64 cr0, u64 cr3, u64 cr4) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci int bad; 24968c2ecf20Sopenharmony_ci u64 pcid; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */ 24998c2ecf20Sopenharmony_ci pcid = 0; 25008c2ecf20Sopenharmony_ci if (cr4 & X86_CR4_PCIDE) { 25018c2ecf20Sopenharmony_ci pcid = cr3 & 0xfff; 25028c2ecf20Sopenharmony_ci cr3 &= ~0xfff; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci bad = ctxt->ops->set_cr(ctxt, 3, cr3); 25068c2ecf20Sopenharmony_ci if (bad) 25078c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci /* 25108c2ecf20Sopenharmony_ci * First enable PAE, long mode needs it before CR0.PG = 1 is set. 25118c2ecf20Sopenharmony_ci * Then enable protected mode. However, PCID cannot be enabled 25128c2ecf20Sopenharmony_ci * if EFER.LMA=0, so set it separately. 25138c2ecf20Sopenharmony_ci */ 25148c2ecf20Sopenharmony_ci bad = ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PCIDE); 25158c2ecf20Sopenharmony_ci if (bad) 25168c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci bad = ctxt->ops->set_cr(ctxt, 0, cr0); 25198c2ecf20Sopenharmony_ci if (bad) 25208c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci if (cr4 & X86_CR4_PCIDE) { 25238c2ecf20Sopenharmony_ci bad = ctxt->ops->set_cr(ctxt, 4, cr4); 25248c2ecf20Sopenharmony_ci if (bad) 25258c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25268c2ecf20Sopenharmony_ci if (pcid) { 25278c2ecf20Sopenharmony_ci bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid); 25288c2ecf20Sopenharmony_ci if (bad) 25298c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25308c2ecf20Sopenharmony_ci } 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci } 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 25358c2ecf20Sopenharmony_ci} 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cistatic int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, 25388c2ecf20Sopenharmony_ci const char *smstate) 25398c2ecf20Sopenharmony_ci{ 25408c2ecf20Sopenharmony_ci struct desc_struct desc; 25418c2ecf20Sopenharmony_ci struct desc_ptr dt; 25428c2ecf20Sopenharmony_ci u16 selector; 25438c2ecf20Sopenharmony_ci u32 val, cr0, cr3, cr4; 25448c2ecf20Sopenharmony_ci int i; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci cr0 = GET_SMSTATE(u32, smstate, 0x7ffc); 25478c2ecf20Sopenharmony_ci cr3 = GET_SMSTATE(u32, smstate, 0x7ff8); 25488c2ecf20Sopenharmony_ci ctxt->eflags = GET_SMSTATE(u32, smstate, 0x7ff4) | X86_EFLAGS_FIXED; 25498c2ecf20Sopenharmony_ci ctxt->_eip = GET_SMSTATE(u32, smstate, 0x7ff0); 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 25528c2ecf20Sopenharmony_ci *reg_write(ctxt, i) = GET_SMSTATE(u32, smstate, 0x7fd0 + i * 4); 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci val = GET_SMSTATE(u32, smstate, 0x7fcc); 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci if (ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1)) 25578c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci val = GET_SMSTATE(u32, smstate, 0x7fc8); 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci if (ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1)) 25628c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u32, smstate, 0x7fc4); 25658c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, 0x7f64)); 25668c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, 0x7f60)); 25678c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smstate, 0x7f5c)); 25688c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, 0, VCPU_SREG_TR); 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u32, smstate, 0x7fc0); 25718c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, 0x7f80)); 25728c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, 0x7f7c)); 25738c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smstate, 0x7f78)); 25748c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, 0, VCPU_SREG_LDTR); 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci dt.address = GET_SMSTATE(u32, smstate, 0x7f74); 25778c2ecf20Sopenharmony_ci dt.size = GET_SMSTATE(u32, smstate, 0x7f70); 25788c2ecf20Sopenharmony_ci ctxt->ops->set_gdt(ctxt, &dt); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci dt.address = GET_SMSTATE(u32, smstate, 0x7f58); 25818c2ecf20Sopenharmony_ci dt.size = GET_SMSTATE(u32, smstate, 0x7f54); 25828c2ecf20Sopenharmony_ci ctxt->ops->set_idt(ctxt, &dt); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 25858c2ecf20Sopenharmony_ci int r = rsm_load_seg_32(ctxt, smstate, i); 25868c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 25878c2ecf20Sopenharmony_ci return r; 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci cr4 = GET_SMSTATE(u32, smstate, 0x7f14); 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smstate, 0x7ef8)); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); 25958c2ecf20Sopenharmony_ci} 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 25988c2ecf20Sopenharmony_cistatic int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, 25998c2ecf20Sopenharmony_ci const char *smstate) 26008c2ecf20Sopenharmony_ci{ 26018c2ecf20Sopenharmony_ci struct desc_struct desc; 26028c2ecf20Sopenharmony_ci struct desc_ptr dt; 26038c2ecf20Sopenharmony_ci u64 val, cr0, cr3, cr4; 26048c2ecf20Sopenharmony_ci u32 base3; 26058c2ecf20Sopenharmony_ci u16 selector; 26068c2ecf20Sopenharmony_ci int i, r; 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 26098c2ecf20Sopenharmony_ci *reg_write(ctxt, i) = GET_SMSTATE(u64, smstate, 0x7ff8 - i * 8); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci ctxt->_eip = GET_SMSTATE(u64, smstate, 0x7f78); 26128c2ecf20Sopenharmony_ci ctxt->eflags = GET_SMSTATE(u32, smstate, 0x7f70) | X86_EFLAGS_FIXED; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci val = GET_SMSTATE(u64, smstate, 0x7f68); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci if (ctxt->ops->set_dr(ctxt, 6, (val & DR6_VOLATILE) | DR6_FIXED_1)) 26178c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci val = GET_SMSTATE(u64, smstate, 0x7f60); 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci if (ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1)) 26228c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci cr0 = GET_SMSTATE(u64, smstate, 0x7f58); 26258c2ecf20Sopenharmony_ci cr3 = GET_SMSTATE(u64, smstate, 0x7f50); 26268c2ecf20Sopenharmony_ci cr4 = GET_SMSTATE(u64, smstate, 0x7f48); 26278c2ecf20Sopenharmony_ci ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smstate, 0x7f00)); 26288c2ecf20Sopenharmony_ci val = GET_SMSTATE(u64, smstate, 0x7ed0); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci if (ctxt->ops->set_msr(ctxt, MSR_EFER, val & ~EFER_LMA)) 26318c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u32, smstate, 0x7e90); 26348c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smstate, 0x7e92) << 8); 26358c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, 0x7e94)); 26368c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, 0x7e98)); 26378c2ecf20Sopenharmony_ci base3 = GET_SMSTATE(u32, smstate, 0x7e9c); 26388c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, base3, VCPU_SREG_TR); 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci dt.size = GET_SMSTATE(u32, smstate, 0x7e84); 26418c2ecf20Sopenharmony_ci dt.address = GET_SMSTATE(u64, smstate, 0x7e88); 26428c2ecf20Sopenharmony_ci ctxt->ops->set_idt(ctxt, &dt); 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci selector = GET_SMSTATE(u32, smstate, 0x7e70); 26458c2ecf20Sopenharmony_ci rsm_set_desc_flags(&desc, GET_SMSTATE(u32, smstate, 0x7e72) << 8); 26468c2ecf20Sopenharmony_ci set_desc_limit(&desc, GET_SMSTATE(u32, smstate, 0x7e74)); 26478c2ecf20Sopenharmony_ci set_desc_base(&desc, GET_SMSTATE(u32, smstate, 0x7e78)); 26488c2ecf20Sopenharmony_ci base3 = GET_SMSTATE(u32, smstate, 0x7e7c); 26498c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, selector, &desc, base3, VCPU_SREG_LDTR); 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci dt.size = GET_SMSTATE(u32, smstate, 0x7e64); 26528c2ecf20Sopenharmony_ci dt.address = GET_SMSTATE(u64, smstate, 0x7e68); 26538c2ecf20Sopenharmony_ci ctxt->ops->set_gdt(ctxt, &dt); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4); 26568c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 26578c2ecf20Sopenharmony_ci return r; 26588c2ecf20Sopenharmony_ci 26598c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 26608c2ecf20Sopenharmony_ci r = rsm_load_seg_64(ctxt, smstate, i); 26618c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 26628c2ecf20Sopenharmony_ci return r; 26638c2ecf20Sopenharmony_ci } 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 26668c2ecf20Sopenharmony_ci} 26678c2ecf20Sopenharmony_ci#endif 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_cistatic int em_rsm(struct x86_emulate_ctxt *ctxt) 26708c2ecf20Sopenharmony_ci{ 26718c2ecf20Sopenharmony_ci unsigned long cr0, cr4, efer; 26728c2ecf20Sopenharmony_ci char buf[512]; 26738c2ecf20Sopenharmony_ci u64 smbase; 26748c2ecf20Sopenharmony_ci int ret; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_MASK) == 0) 26778c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci smbase = ctxt->ops->get_smbase(ctxt); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci ret = ctxt->ops->read_phys(ctxt, smbase + 0xfe00, buf, sizeof(buf)); 26828c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 26838c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci if ((ctxt->ops->get_hflags(ctxt) & X86EMUL_SMM_INSIDE_NMI_MASK) == 0) 26868c2ecf20Sopenharmony_ci ctxt->ops->set_nmi_mask(ctxt, false); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci ctxt->ops->set_hflags(ctxt, ctxt->ops->get_hflags(ctxt) & 26898c2ecf20Sopenharmony_ci ~(X86EMUL_SMM_INSIDE_NMI_MASK | X86EMUL_SMM_MASK)); 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci /* 26928c2ecf20Sopenharmony_ci * Get back to real mode, to prepare a safe state in which to load 26938c2ecf20Sopenharmony_ci * CR0/CR3/CR4/EFER. It's all a bit more complicated if the vCPU 26948c2ecf20Sopenharmony_ci * supports long mode. 26958c2ecf20Sopenharmony_ci */ 26968c2ecf20Sopenharmony_ci if (emulator_has_longmode(ctxt)) { 26978c2ecf20Sopenharmony_ci struct desc_struct cs_desc; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci /* Zero CR4.PCIDE before CR0.PG. */ 27008c2ecf20Sopenharmony_ci cr4 = ctxt->ops->get_cr(ctxt, 4); 27018c2ecf20Sopenharmony_ci if (cr4 & X86_CR4_PCIDE) 27028c2ecf20Sopenharmony_ci ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PCIDE); 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci /* A 32-bit code segment is required to clear EFER.LMA. */ 27058c2ecf20Sopenharmony_ci memset(&cs_desc, 0, sizeof(cs_desc)); 27068c2ecf20Sopenharmony_ci cs_desc.type = 0xb; 27078c2ecf20Sopenharmony_ci cs_desc.s = cs_desc.g = cs_desc.p = 1; 27088c2ecf20Sopenharmony_ci ctxt->ops->set_segment(ctxt, 0, &cs_desc, 0, VCPU_SREG_CS); 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci /* For the 64-bit case, this will clear EFER.LMA. */ 27128c2ecf20Sopenharmony_ci cr0 = ctxt->ops->get_cr(ctxt, 0); 27138c2ecf20Sopenharmony_ci if (cr0 & X86_CR0_PE) 27148c2ecf20Sopenharmony_ci ctxt->ops->set_cr(ctxt, 0, cr0 & ~(X86_CR0_PG | X86_CR0_PE)); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci if (emulator_has_longmode(ctxt)) { 27178c2ecf20Sopenharmony_ci /* Clear CR4.PAE before clearing EFER.LME. */ 27188c2ecf20Sopenharmony_ci cr4 = ctxt->ops->get_cr(ctxt, 4); 27198c2ecf20Sopenharmony_ci if (cr4 & X86_CR4_PAE) 27208c2ecf20Sopenharmony_ci ctxt->ops->set_cr(ctxt, 4, cr4 & ~X86_CR4_PAE); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci /* And finally go back to 32-bit mode. */ 27238c2ecf20Sopenharmony_ci efer = 0; 27248c2ecf20Sopenharmony_ci ctxt->ops->set_msr(ctxt, MSR_EFER, efer); 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci /* 27288c2ecf20Sopenharmony_ci * Give pre_leave_smm() a chance to make ISA-specific changes to the 27298c2ecf20Sopenharmony_ci * vCPU state (e.g. enter guest mode) before loading state from the SMM 27308c2ecf20Sopenharmony_ci * state-save area. 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_ci if (ctxt->ops->pre_leave_smm(ctxt, buf)) 27338c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 27368c2ecf20Sopenharmony_ci if (emulator_has_longmode(ctxt)) 27378c2ecf20Sopenharmony_ci ret = rsm_load_state_64(ctxt, buf); 27388c2ecf20Sopenharmony_ci else 27398c2ecf20Sopenharmony_ci#endif 27408c2ecf20Sopenharmony_ci ret = rsm_load_state_32(ctxt, buf); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) { 27438c2ecf20Sopenharmony_ci /* FIXME: should triple fault */ 27448c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 27458c2ecf20Sopenharmony_ci } 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci ctxt->ops->post_leave_smm(ctxt); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 27508c2ecf20Sopenharmony_ci} 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_cistatic void 27538c2ecf20Sopenharmony_cisetup_syscalls_segments(struct x86_emulate_ctxt *ctxt, 27548c2ecf20Sopenharmony_ci struct desc_struct *cs, struct desc_struct *ss) 27558c2ecf20Sopenharmony_ci{ 27568c2ecf20Sopenharmony_ci cs->l = 0; /* will be adjusted later */ 27578c2ecf20Sopenharmony_ci set_desc_base(cs, 0); /* flat segment */ 27588c2ecf20Sopenharmony_ci cs->g = 1; /* 4kb granularity */ 27598c2ecf20Sopenharmony_ci set_desc_limit(cs, 0xfffff); /* 4GB limit */ 27608c2ecf20Sopenharmony_ci cs->type = 0x0b; /* Read, Execute, Accessed */ 27618c2ecf20Sopenharmony_ci cs->s = 1; 27628c2ecf20Sopenharmony_ci cs->dpl = 0; /* will be adjusted later */ 27638c2ecf20Sopenharmony_ci cs->p = 1; 27648c2ecf20Sopenharmony_ci cs->d = 1; 27658c2ecf20Sopenharmony_ci cs->avl = 0; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci set_desc_base(ss, 0); /* flat segment */ 27688c2ecf20Sopenharmony_ci set_desc_limit(ss, 0xfffff); /* 4GB limit */ 27698c2ecf20Sopenharmony_ci ss->g = 1; /* 4kb granularity */ 27708c2ecf20Sopenharmony_ci ss->s = 1; 27718c2ecf20Sopenharmony_ci ss->type = 0x03; /* Read/Write, Accessed */ 27728c2ecf20Sopenharmony_ci ss->d = 1; /* 32bit stack segment */ 27738c2ecf20Sopenharmony_ci ss->dpl = 0; 27748c2ecf20Sopenharmony_ci ss->p = 1; 27758c2ecf20Sopenharmony_ci ss->l = 0; 27768c2ecf20Sopenharmony_ci ss->avl = 0; 27778c2ecf20Sopenharmony_ci} 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_cistatic bool vendor_intel(struct x86_emulate_ctxt *ctxt) 27808c2ecf20Sopenharmony_ci{ 27818c2ecf20Sopenharmony_ci u32 eax, ebx, ecx, edx; 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci eax = ecx = 0; 27848c2ecf20Sopenharmony_ci ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true); 27858c2ecf20Sopenharmony_ci return is_guest_vendor_intel(ebx, ecx, edx); 27868c2ecf20Sopenharmony_ci} 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_cistatic bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt) 27898c2ecf20Sopenharmony_ci{ 27908c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 27918c2ecf20Sopenharmony_ci u32 eax, ebx, ecx, edx; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_ci /* 27948c2ecf20Sopenharmony_ci * syscall should always be enabled in longmode - so only become 27958c2ecf20Sopenharmony_ci * vendor specific (cpuid) if other modes are active... 27968c2ecf20Sopenharmony_ci */ 27978c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 27988c2ecf20Sopenharmony_ci return true; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci eax = 0x00000000; 28018c2ecf20Sopenharmony_ci ecx = 0x00000000; 28028c2ecf20Sopenharmony_ci ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true); 28038c2ecf20Sopenharmony_ci /* 28048c2ecf20Sopenharmony_ci * remark: Intel CPUs only support "syscall" in 64bit longmode. Also a 28058c2ecf20Sopenharmony_ci * 64bit guest with a 32bit compat-app running will #UD !! While this 28068c2ecf20Sopenharmony_ci * behaviour can be fixed (by emulating) into AMD response - CPUs of 28078c2ecf20Sopenharmony_ci * AMD can't behave like Intel. 28088c2ecf20Sopenharmony_ci */ 28098c2ecf20Sopenharmony_ci if (is_guest_vendor_intel(ebx, ecx, edx)) 28108c2ecf20Sopenharmony_ci return false; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci if (is_guest_vendor_amd(ebx, ecx, edx) || 28138c2ecf20Sopenharmony_ci is_guest_vendor_hygon(ebx, ecx, edx)) 28148c2ecf20Sopenharmony_ci return true; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci /* 28178c2ecf20Sopenharmony_ci * default: (not Intel, not AMD, not Hygon), apply Intel's 28188c2ecf20Sopenharmony_ci * stricter rules... 28198c2ecf20Sopenharmony_ci */ 28208c2ecf20Sopenharmony_ci return false; 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_cistatic int em_syscall(struct x86_emulate_ctxt *ctxt) 28248c2ecf20Sopenharmony_ci{ 28258c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 28268c2ecf20Sopenharmony_ci struct desc_struct cs, ss; 28278c2ecf20Sopenharmony_ci u64 msr_data; 28288c2ecf20Sopenharmony_ci u16 cs_sel, ss_sel; 28298c2ecf20Sopenharmony_ci u64 efer = 0; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci /* syscall is not available in real mode */ 28328c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_REAL || 28338c2ecf20Sopenharmony_ci ctxt->mode == X86EMUL_MODE_VM86) 28348c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci if (!(em_syscall_is_enabled(ctxt))) 28378c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_EFER, &efer); 28408c2ecf20Sopenharmony_ci if (!(efer & EFER_SCE)) 28418c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci setup_syscalls_segments(ctxt, &cs, &ss); 28448c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_STAR, &msr_data); 28458c2ecf20Sopenharmony_ci msr_data >>= 32; 28468c2ecf20Sopenharmony_ci cs_sel = (u16)(msr_data & 0xfffc); 28478c2ecf20Sopenharmony_ci ss_sel = (u16)(msr_data + 8); 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci if (efer & EFER_LMA) { 28508c2ecf20Sopenharmony_ci cs.d = 0; 28518c2ecf20Sopenharmony_ci cs.l = 1; 28528c2ecf20Sopenharmony_ci } 28538c2ecf20Sopenharmony_ci ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); 28548c2ecf20Sopenharmony_ci ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RCX) = ctxt->_eip; 28578c2ecf20Sopenharmony_ci if (efer & EFER_LMA) { 28588c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 28598c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_R11) = ctxt->eflags; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci ops->get_msr(ctxt, 28628c2ecf20Sopenharmony_ci ctxt->mode == X86EMUL_MODE_PROT64 ? 28638c2ecf20Sopenharmony_ci MSR_LSTAR : MSR_CSTAR, &msr_data); 28648c2ecf20Sopenharmony_ci ctxt->_eip = msr_data; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_SYSCALL_MASK, &msr_data); 28678c2ecf20Sopenharmony_ci ctxt->eflags &= ~msr_data; 28688c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_FIXED; 28698c2ecf20Sopenharmony_ci#endif 28708c2ecf20Sopenharmony_ci } else { 28718c2ecf20Sopenharmony_ci /* legacy mode */ 28728c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_STAR, &msr_data); 28738c2ecf20Sopenharmony_ci ctxt->_eip = (u32)msr_data; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci ctxt->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_IF); 28768c2ecf20Sopenharmony_ci } 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci ctxt->tf = (ctxt->eflags & X86_EFLAGS_TF) != 0; 28798c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 28808c2ecf20Sopenharmony_ci} 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_cistatic int em_sysenter(struct x86_emulate_ctxt *ctxt) 28838c2ecf20Sopenharmony_ci{ 28848c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 28858c2ecf20Sopenharmony_ci struct desc_struct cs, ss; 28868c2ecf20Sopenharmony_ci u64 msr_data; 28878c2ecf20Sopenharmony_ci u16 cs_sel, ss_sel; 28888c2ecf20Sopenharmony_ci u64 efer = 0; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_EFER, &efer); 28918c2ecf20Sopenharmony_ci /* inject #GP if in real mode */ 28928c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_REAL) 28938c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci /* 28968c2ecf20Sopenharmony_ci * Not recognized on AMD in compat mode (but is recognized in legacy 28978c2ecf20Sopenharmony_ci * mode). 28988c2ecf20Sopenharmony_ci */ 28998c2ecf20Sopenharmony_ci if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) 29008c2ecf20Sopenharmony_ci && !vendor_intel(ctxt)) 29018c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci /* sysenter/sysexit have not been tested in 64bit mode. */ 29048c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 29058c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); 29088c2ecf20Sopenharmony_ci if ((msr_data & 0xfffc) == 0x0) 29098c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci setup_syscalls_segments(ctxt, &cs, &ss); 29128c2ecf20Sopenharmony_ci ctxt->eflags &= ~(X86_EFLAGS_VM | X86_EFLAGS_IF); 29138c2ecf20Sopenharmony_ci cs_sel = (u16)msr_data & ~SEGMENT_RPL_MASK; 29148c2ecf20Sopenharmony_ci ss_sel = cs_sel + 8; 29158c2ecf20Sopenharmony_ci if (efer & EFER_LMA) { 29168c2ecf20Sopenharmony_ci cs.d = 0; 29178c2ecf20Sopenharmony_ci cs.l = 1; 29188c2ecf20Sopenharmony_ci } 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); 29218c2ecf20Sopenharmony_ci ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data); 29248c2ecf20Sopenharmony_ci ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data); 29278c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data : 29288c2ecf20Sopenharmony_ci (u32)msr_data; 29298c2ecf20Sopenharmony_ci if (efer & EFER_LMA) 29308c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_PROT64; 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_cistatic int em_sysexit(struct x86_emulate_ctxt *ctxt) 29368c2ecf20Sopenharmony_ci{ 29378c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 29388c2ecf20Sopenharmony_ci struct desc_struct cs, ss; 29398c2ecf20Sopenharmony_ci u64 msr_data, rcx, rdx; 29408c2ecf20Sopenharmony_ci int usermode; 29418c2ecf20Sopenharmony_ci u16 cs_sel = 0, ss_sel = 0; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci /* inject #GP if in real mode or Virtual 8086 mode */ 29448c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_REAL || 29458c2ecf20Sopenharmony_ci ctxt->mode == X86EMUL_MODE_VM86) 29468c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci setup_syscalls_segments(ctxt, &cs, &ss); 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci if ((ctxt->rex_prefix & 0x8) != 0x0) 29518c2ecf20Sopenharmony_ci usermode = X86EMUL_MODE_PROT64; 29528c2ecf20Sopenharmony_ci else 29538c2ecf20Sopenharmony_ci usermode = X86EMUL_MODE_PROT32; 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci rcx = reg_read(ctxt, VCPU_REGS_RCX); 29568c2ecf20Sopenharmony_ci rdx = reg_read(ctxt, VCPU_REGS_RDX); 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci cs.dpl = 3; 29598c2ecf20Sopenharmony_ci ss.dpl = 3; 29608c2ecf20Sopenharmony_ci ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data); 29618c2ecf20Sopenharmony_ci switch (usermode) { 29628c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT32: 29638c2ecf20Sopenharmony_ci cs_sel = (u16)(msr_data + 16); 29648c2ecf20Sopenharmony_ci if ((msr_data & 0xfffc) == 0x0) 29658c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 29668c2ecf20Sopenharmony_ci ss_sel = (u16)(msr_data + 24); 29678c2ecf20Sopenharmony_ci rcx = (u32)rcx; 29688c2ecf20Sopenharmony_ci rdx = (u32)rdx; 29698c2ecf20Sopenharmony_ci break; 29708c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 29718c2ecf20Sopenharmony_ci cs_sel = (u16)(msr_data + 32); 29728c2ecf20Sopenharmony_ci if (msr_data == 0x0) 29738c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 29748c2ecf20Sopenharmony_ci ss_sel = cs_sel + 8; 29758c2ecf20Sopenharmony_ci cs.d = 0; 29768c2ecf20Sopenharmony_ci cs.l = 1; 29778c2ecf20Sopenharmony_ci if (emul_is_noncanonical_address(rcx, ctxt) || 29788c2ecf20Sopenharmony_ci emul_is_noncanonical_address(rdx, ctxt)) 29798c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 29808c2ecf20Sopenharmony_ci break; 29818c2ecf20Sopenharmony_ci } 29828c2ecf20Sopenharmony_ci cs_sel |= SEGMENT_RPL_MASK; 29838c2ecf20Sopenharmony_ci ss_sel |= SEGMENT_RPL_MASK; 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS); 29868c2ecf20Sopenharmony_ci ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci ctxt->_eip = rdx; 29898c2ecf20Sopenharmony_ci ctxt->mode = usermode; 29908c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSP) = rcx; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 29938c2ecf20Sopenharmony_ci} 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_cistatic bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) 29968c2ecf20Sopenharmony_ci{ 29978c2ecf20Sopenharmony_ci int iopl; 29988c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_REAL) 29998c2ecf20Sopenharmony_ci return false; 30008c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_VM86) 30018c2ecf20Sopenharmony_ci return true; 30028c2ecf20Sopenharmony_ci iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> X86_EFLAGS_IOPL_BIT; 30038c2ecf20Sopenharmony_ci return ctxt->ops->cpl(ctxt) > iopl; 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci#define VMWARE_PORT_VMPORT (0x5658) 30078c2ecf20Sopenharmony_ci#define VMWARE_PORT_VMRPC (0x5659) 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_cistatic bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, 30108c2ecf20Sopenharmony_ci u16 port, u16 len) 30118c2ecf20Sopenharmony_ci{ 30128c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 30138c2ecf20Sopenharmony_ci struct desc_struct tr_seg; 30148c2ecf20Sopenharmony_ci u32 base3; 30158c2ecf20Sopenharmony_ci int r; 30168c2ecf20Sopenharmony_ci u16 tr, io_bitmap_ptr, perm, bit_idx = port & 0x7; 30178c2ecf20Sopenharmony_ci unsigned mask = (1 << len) - 1; 30188c2ecf20Sopenharmony_ci unsigned long base; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci /* 30218c2ecf20Sopenharmony_ci * VMware allows access to these ports even if denied 30228c2ecf20Sopenharmony_ci * by TSS I/O permission bitmap. Mimic behavior. 30238c2ecf20Sopenharmony_ci */ 30248c2ecf20Sopenharmony_ci if (enable_vmware_backdoor && 30258c2ecf20Sopenharmony_ci ((port == VMWARE_PORT_VMPORT) || (port == VMWARE_PORT_VMRPC))) 30268c2ecf20Sopenharmony_ci return true; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci ops->get_segment(ctxt, &tr, &tr_seg, &base3, VCPU_SREG_TR); 30298c2ecf20Sopenharmony_ci if (!tr_seg.p) 30308c2ecf20Sopenharmony_ci return false; 30318c2ecf20Sopenharmony_ci if (desc_limit_scaled(&tr_seg) < 103) 30328c2ecf20Sopenharmony_ci return false; 30338c2ecf20Sopenharmony_ci base = get_desc_base(&tr_seg); 30348c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 30358c2ecf20Sopenharmony_ci base |= ((u64)base3) << 32; 30368c2ecf20Sopenharmony_ci#endif 30378c2ecf20Sopenharmony_ci r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true); 30388c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 30398c2ecf20Sopenharmony_ci return false; 30408c2ecf20Sopenharmony_ci if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) 30418c2ecf20Sopenharmony_ci return false; 30428c2ecf20Sopenharmony_ci r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true); 30438c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 30448c2ecf20Sopenharmony_ci return false; 30458c2ecf20Sopenharmony_ci if ((perm >> bit_idx) & mask) 30468c2ecf20Sopenharmony_ci return false; 30478c2ecf20Sopenharmony_ci return true; 30488c2ecf20Sopenharmony_ci} 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_cistatic bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, 30518c2ecf20Sopenharmony_ci u16 port, u16 len) 30528c2ecf20Sopenharmony_ci{ 30538c2ecf20Sopenharmony_ci if (ctxt->perm_ok) 30548c2ecf20Sopenharmony_ci return true; 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci if (emulator_bad_iopl(ctxt)) 30578c2ecf20Sopenharmony_ci if (!emulator_io_port_access_allowed(ctxt, port, len)) 30588c2ecf20Sopenharmony_ci return false; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci ctxt->perm_ok = true; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci return true; 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_cistatic void string_registers_quirk(struct x86_emulate_ctxt *ctxt) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci /* 30688c2ecf20Sopenharmony_ci * Intel CPUs mask the counter and pointers in quite strange 30698c2ecf20Sopenharmony_ci * manner when ECX is zero due to REP-string optimizations. 30708c2ecf20Sopenharmony_ci */ 30718c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 30728c2ecf20Sopenharmony_ci if (ctxt->ad_bytes != 4 || !vendor_intel(ctxt)) 30738c2ecf20Sopenharmony_ci return; 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RCX) = 0; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci switch (ctxt->b) { 30788c2ecf20Sopenharmony_ci case 0xa4: /* movsb */ 30798c2ecf20Sopenharmony_ci case 0xa5: /* movsd/w */ 30808c2ecf20Sopenharmony_ci *reg_rmw(ctxt, VCPU_REGS_RSI) &= (u32)-1; 30818c2ecf20Sopenharmony_ci fallthrough; 30828c2ecf20Sopenharmony_ci case 0xaa: /* stosb */ 30838c2ecf20Sopenharmony_ci case 0xab: /* stosd/w */ 30848c2ecf20Sopenharmony_ci *reg_rmw(ctxt, VCPU_REGS_RDI) &= (u32)-1; 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci#endif 30878c2ecf20Sopenharmony_ci} 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_cistatic void save_state_to_tss16(struct x86_emulate_ctxt *ctxt, 30908c2ecf20Sopenharmony_ci struct tss_segment_16 *tss) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci tss->ip = ctxt->_eip; 30938c2ecf20Sopenharmony_ci tss->flag = ctxt->eflags; 30948c2ecf20Sopenharmony_ci tss->ax = reg_read(ctxt, VCPU_REGS_RAX); 30958c2ecf20Sopenharmony_ci tss->cx = reg_read(ctxt, VCPU_REGS_RCX); 30968c2ecf20Sopenharmony_ci tss->dx = reg_read(ctxt, VCPU_REGS_RDX); 30978c2ecf20Sopenharmony_ci tss->bx = reg_read(ctxt, VCPU_REGS_RBX); 30988c2ecf20Sopenharmony_ci tss->sp = reg_read(ctxt, VCPU_REGS_RSP); 30998c2ecf20Sopenharmony_ci tss->bp = reg_read(ctxt, VCPU_REGS_RBP); 31008c2ecf20Sopenharmony_ci tss->si = reg_read(ctxt, VCPU_REGS_RSI); 31018c2ecf20Sopenharmony_ci tss->di = reg_read(ctxt, VCPU_REGS_RDI); 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); 31048c2ecf20Sopenharmony_ci tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); 31058c2ecf20Sopenharmony_ci tss->ss = get_segment_selector(ctxt, VCPU_SREG_SS); 31068c2ecf20Sopenharmony_ci tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS); 31078c2ecf20Sopenharmony_ci tss->ldt = get_segment_selector(ctxt, VCPU_SREG_LDTR); 31088c2ecf20Sopenharmony_ci} 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_cistatic int load_state_from_tss16(struct x86_emulate_ctxt *ctxt, 31118c2ecf20Sopenharmony_ci struct tss_segment_16 *tss) 31128c2ecf20Sopenharmony_ci{ 31138c2ecf20Sopenharmony_ci int ret; 31148c2ecf20Sopenharmony_ci u8 cpl; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci ctxt->_eip = tss->ip; 31178c2ecf20Sopenharmony_ci ctxt->eflags = tss->flag | 2; 31188c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = tss->ax; 31198c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RCX) = tss->cx; 31208c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = tss->dx; 31218c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RBX) = tss->bx; 31228c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSP) = tss->sp; 31238c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RBP) = tss->bp; 31248c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSI) = tss->si; 31258c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDI) = tss->di; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci /* 31288c2ecf20Sopenharmony_ci * SDM says that segment selectors are loaded before segment 31298c2ecf20Sopenharmony_ci * descriptors 31308c2ecf20Sopenharmony_ci */ 31318c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ldt, VCPU_SREG_LDTR); 31328c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->es, VCPU_SREG_ES); 31338c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->cs, VCPU_SREG_CS); 31348c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ss, VCPU_SREG_SS); 31358c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci cpl = tss->cs & 3; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci /* 31408c2ecf20Sopenharmony_ci * Now load segment descriptors. If fault happens at this stage 31418c2ecf20Sopenharmony_ci * it is handled in a context of new task 31428c2ecf20Sopenharmony_ci */ 31438c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR, cpl, 31448c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 31458c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31468c2ecf20Sopenharmony_ci return ret; 31478c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl, 31488c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 31498c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31508c2ecf20Sopenharmony_ci return ret; 31518c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl, 31528c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 31538c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31548c2ecf20Sopenharmony_ci return ret; 31558c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl, 31568c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 31578c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31588c2ecf20Sopenharmony_ci return ret; 31598c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl, 31608c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 31618c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31628c2ecf20Sopenharmony_ci return ret; 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 31658c2ecf20Sopenharmony_ci} 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_cistatic int task_switch_16(struct x86_emulate_ctxt *ctxt, 31688c2ecf20Sopenharmony_ci u16 tss_selector, u16 old_tss_sel, 31698c2ecf20Sopenharmony_ci ulong old_tss_base, struct desc_struct *new_desc) 31708c2ecf20Sopenharmony_ci{ 31718c2ecf20Sopenharmony_ci struct tss_segment_16 tss_seg; 31728c2ecf20Sopenharmony_ci int ret; 31738c2ecf20Sopenharmony_ci u32 new_tss_base = get_desc_base(new_desc); 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof(tss_seg)); 31768c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31778c2ecf20Sopenharmony_ci return ret; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci save_state_to_tss16(ctxt, &tss_seg); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof(tss_seg)); 31828c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31838c2ecf20Sopenharmony_ci return ret; 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof(tss_seg)); 31868c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31878c2ecf20Sopenharmony_ci return ret; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci if (old_tss_sel != 0xffff) { 31908c2ecf20Sopenharmony_ci tss_seg.prev_task_link = old_tss_sel; 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci ret = linear_write_system(ctxt, new_tss_base, 31938c2ecf20Sopenharmony_ci &tss_seg.prev_task_link, 31948c2ecf20Sopenharmony_ci sizeof(tss_seg.prev_task_link)); 31958c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 31968c2ecf20Sopenharmony_ci return ret; 31978c2ecf20Sopenharmony_ci } 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci return load_state_from_tss16(ctxt, &tss_seg); 32008c2ecf20Sopenharmony_ci} 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_cistatic void save_state_to_tss32(struct x86_emulate_ctxt *ctxt, 32038c2ecf20Sopenharmony_ci struct tss_segment_32 *tss) 32048c2ecf20Sopenharmony_ci{ 32058c2ecf20Sopenharmony_ci /* CR3 and ldt selector are not saved intentionally */ 32068c2ecf20Sopenharmony_ci tss->eip = ctxt->_eip; 32078c2ecf20Sopenharmony_ci tss->eflags = ctxt->eflags; 32088c2ecf20Sopenharmony_ci tss->eax = reg_read(ctxt, VCPU_REGS_RAX); 32098c2ecf20Sopenharmony_ci tss->ecx = reg_read(ctxt, VCPU_REGS_RCX); 32108c2ecf20Sopenharmony_ci tss->edx = reg_read(ctxt, VCPU_REGS_RDX); 32118c2ecf20Sopenharmony_ci tss->ebx = reg_read(ctxt, VCPU_REGS_RBX); 32128c2ecf20Sopenharmony_ci tss->esp = reg_read(ctxt, VCPU_REGS_RSP); 32138c2ecf20Sopenharmony_ci tss->ebp = reg_read(ctxt, VCPU_REGS_RBP); 32148c2ecf20Sopenharmony_ci tss->esi = reg_read(ctxt, VCPU_REGS_RSI); 32158c2ecf20Sopenharmony_ci tss->edi = reg_read(ctxt, VCPU_REGS_RDI); 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci tss->es = get_segment_selector(ctxt, VCPU_SREG_ES); 32188c2ecf20Sopenharmony_ci tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS); 32198c2ecf20Sopenharmony_ci tss->ss = get_segment_selector(ctxt, VCPU_SREG_SS); 32208c2ecf20Sopenharmony_ci tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS); 32218c2ecf20Sopenharmony_ci tss->fs = get_segment_selector(ctxt, VCPU_SREG_FS); 32228c2ecf20Sopenharmony_ci tss->gs = get_segment_selector(ctxt, VCPU_SREG_GS); 32238c2ecf20Sopenharmony_ci} 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_cistatic int load_state_from_tss32(struct x86_emulate_ctxt *ctxt, 32268c2ecf20Sopenharmony_ci struct tss_segment_32 *tss) 32278c2ecf20Sopenharmony_ci{ 32288c2ecf20Sopenharmony_ci int ret; 32298c2ecf20Sopenharmony_ci u8 cpl; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci if (ctxt->ops->set_cr(ctxt, 3, tss->cr3)) 32328c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 32338c2ecf20Sopenharmony_ci ctxt->_eip = tss->eip; 32348c2ecf20Sopenharmony_ci ctxt->eflags = tss->eflags | 2; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci /* General purpose registers */ 32378c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = tss->eax; 32388c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RCX) = tss->ecx; 32398c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = tss->edx; 32408c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RBX) = tss->ebx; 32418c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSP) = tss->esp; 32428c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RBP) = tss->ebp; 32438c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RSI) = tss->esi; 32448c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDI) = tss->edi; 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci /* 32478c2ecf20Sopenharmony_ci * SDM says that segment selectors are loaded before segment 32488c2ecf20Sopenharmony_ci * descriptors. This is important because CPL checks will 32498c2ecf20Sopenharmony_ci * use CS.RPL. 32508c2ecf20Sopenharmony_ci */ 32518c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ldt_selector, VCPU_SREG_LDTR); 32528c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->es, VCPU_SREG_ES); 32538c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->cs, VCPU_SREG_CS); 32548c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ss, VCPU_SREG_SS); 32558c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS); 32568c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->fs, VCPU_SREG_FS); 32578c2ecf20Sopenharmony_ci set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci /* 32608c2ecf20Sopenharmony_ci * If we're switching between Protected Mode and VM86, we need to make 32618c2ecf20Sopenharmony_ci * sure to update the mode before loading the segment descriptors so 32628c2ecf20Sopenharmony_ci * that the selectors are interpreted correctly. 32638c2ecf20Sopenharmony_ci */ 32648c2ecf20Sopenharmony_ci if (ctxt->eflags & X86_EFLAGS_VM) { 32658c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_VM86; 32668c2ecf20Sopenharmony_ci cpl = 3; 32678c2ecf20Sopenharmony_ci } else { 32688c2ecf20Sopenharmony_ci ctxt->mode = X86EMUL_MODE_PROT32; 32698c2ecf20Sopenharmony_ci cpl = tss->cs & 3; 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci /* 32738c2ecf20Sopenharmony_ci * Now load segment descriptors. If fault happenes at this stage 32748c2ecf20Sopenharmony_ci * it is handled in a context of new task 32758c2ecf20Sopenharmony_ci */ 32768c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ldt_selector, VCPU_SREG_LDTR, 32778c2ecf20Sopenharmony_ci cpl, X86_TRANSFER_TASK_SWITCH, NULL); 32788c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32798c2ecf20Sopenharmony_ci return ret; 32808c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl, 32818c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 32828c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32838c2ecf20Sopenharmony_ci return ret; 32848c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl, 32858c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 32868c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32878c2ecf20Sopenharmony_ci return ret; 32888c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl, 32898c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 32908c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32918c2ecf20Sopenharmony_ci return ret; 32928c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl, 32938c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 32948c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32958c2ecf20Sopenharmony_ci return ret; 32968c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->fs, VCPU_SREG_FS, cpl, 32978c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 32988c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 32998c2ecf20Sopenharmony_ci return ret; 33008c2ecf20Sopenharmony_ci ret = __load_segment_descriptor(ctxt, tss->gs, VCPU_SREG_GS, cpl, 33018c2ecf20Sopenharmony_ci X86_TRANSFER_TASK_SWITCH, NULL); 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci return ret; 33048c2ecf20Sopenharmony_ci} 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_cistatic int task_switch_32(struct x86_emulate_ctxt *ctxt, 33078c2ecf20Sopenharmony_ci u16 tss_selector, u16 old_tss_sel, 33088c2ecf20Sopenharmony_ci ulong old_tss_base, struct desc_struct *new_desc) 33098c2ecf20Sopenharmony_ci{ 33108c2ecf20Sopenharmony_ci struct tss_segment_32 tss_seg; 33118c2ecf20Sopenharmony_ci int ret; 33128c2ecf20Sopenharmony_ci u32 new_tss_base = get_desc_base(new_desc); 33138c2ecf20Sopenharmony_ci u32 eip_offset = offsetof(struct tss_segment_32, eip); 33148c2ecf20Sopenharmony_ci u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof(tss_seg)); 33178c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33188c2ecf20Sopenharmony_ci return ret; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci save_state_to_tss32(ctxt, &tss_seg); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci /* Only GP registers and segment selectors are saved */ 33238c2ecf20Sopenharmony_ci ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip, 33248c2ecf20Sopenharmony_ci ldt_sel_offset - eip_offset); 33258c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33268c2ecf20Sopenharmony_ci return ret; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof(tss_seg)); 33298c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33308c2ecf20Sopenharmony_ci return ret; 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci if (old_tss_sel != 0xffff) { 33338c2ecf20Sopenharmony_ci tss_seg.prev_task_link = old_tss_sel; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci ret = linear_write_system(ctxt, new_tss_base, 33368c2ecf20Sopenharmony_ci &tss_seg.prev_task_link, 33378c2ecf20Sopenharmony_ci sizeof(tss_seg.prev_task_link)); 33388c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33398c2ecf20Sopenharmony_ci return ret; 33408c2ecf20Sopenharmony_ci } 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci return load_state_from_tss32(ctxt, &tss_seg); 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cistatic int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, 33468c2ecf20Sopenharmony_ci u16 tss_selector, int idt_index, int reason, 33478c2ecf20Sopenharmony_ci bool has_error_code, u32 error_code) 33488c2ecf20Sopenharmony_ci{ 33498c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 33508c2ecf20Sopenharmony_ci struct desc_struct curr_tss_desc, next_tss_desc; 33518c2ecf20Sopenharmony_ci int ret; 33528c2ecf20Sopenharmony_ci u16 old_tss_sel = get_segment_selector(ctxt, VCPU_SREG_TR); 33538c2ecf20Sopenharmony_ci ulong old_tss_base = 33548c2ecf20Sopenharmony_ci ops->get_cached_segment_base(ctxt, VCPU_SREG_TR); 33558c2ecf20Sopenharmony_ci u32 desc_limit; 33568c2ecf20Sopenharmony_ci ulong desc_addr, dr7; 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci /* FIXME: old_tss_base == ~0 ? */ 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci ret = read_segment_descriptor(ctxt, tss_selector, &next_tss_desc, &desc_addr); 33618c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33628c2ecf20Sopenharmony_ci return ret; 33638c2ecf20Sopenharmony_ci ret = read_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc, &desc_addr); 33648c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33658c2ecf20Sopenharmony_ci return ret; 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci /* FIXME: check that next_tss_desc is tss */ 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci /* 33708c2ecf20Sopenharmony_ci * Check privileges. The three cases are task switch caused by... 33718c2ecf20Sopenharmony_ci * 33728c2ecf20Sopenharmony_ci * 1. jmp/call/int to task gate: Check against DPL of the task gate 33738c2ecf20Sopenharmony_ci * 2. Exception/IRQ/iret: No check is performed 33748c2ecf20Sopenharmony_ci * 3. jmp/call to TSS/task-gate: No check is performed since the 33758c2ecf20Sopenharmony_ci * hardware checks it before exiting. 33768c2ecf20Sopenharmony_ci */ 33778c2ecf20Sopenharmony_ci if (reason == TASK_SWITCH_GATE) { 33788c2ecf20Sopenharmony_ci if (idt_index != -1) { 33798c2ecf20Sopenharmony_ci /* Software interrupts */ 33808c2ecf20Sopenharmony_ci struct desc_struct task_gate_desc; 33818c2ecf20Sopenharmony_ci int dpl; 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci ret = read_interrupt_descriptor(ctxt, idt_index, 33848c2ecf20Sopenharmony_ci &task_gate_desc); 33858c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 33868c2ecf20Sopenharmony_ci return ret; 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci dpl = task_gate_desc.dpl; 33898c2ecf20Sopenharmony_ci if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl) 33908c2ecf20Sopenharmony_ci return emulate_gp(ctxt, (idt_index << 3) | 0x2); 33918c2ecf20Sopenharmony_ci } 33928c2ecf20Sopenharmony_ci } 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci desc_limit = desc_limit_scaled(&next_tss_desc); 33958c2ecf20Sopenharmony_ci if (!next_tss_desc.p || 33968c2ecf20Sopenharmony_ci ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || 33978c2ecf20Sopenharmony_ci desc_limit < 0x2b)) { 33988c2ecf20Sopenharmony_ci return emulate_ts(ctxt, tss_selector & 0xfffc); 33998c2ecf20Sopenharmony_ci } 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci if (reason == TASK_SWITCH_IRET || reason == TASK_SWITCH_JMP) { 34028c2ecf20Sopenharmony_ci curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ 34038c2ecf20Sopenharmony_ci write_segment_descriptor(ctxt, old_tss_sel, &curr_tss_desc); 34048c2ecf20Sopenharmony_ci } 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci if (reason == TASK_SWITCH_IRET) 34078c2ecf20Sopenharmony_ci ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT; 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci /* set back link to prev task only if NT bit is set in eflags 34108c2ecf20Sopenharmony_ci note that old_tss_sel is not used after this point */ 34118c2ecf20Sopenharmony_ci if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE) 34128c2ecf20Sopenharmony_ci old_tss_sel = 0xffff; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (next_tss_desc.type & 8) 34158c2ecf20Sopenharmony_ci ret = task_switch_32(ctxt, tss_selector, old_tss_sel, 34168c2ecf20Sopenharmony_ci old_tss_base, &next_tss_desc); 34178c2ecf20Sopenharmony_ci else 34188c2ecf20Sopenharmony_ci ret = task_switch_16(ctxt, tss_selector, old_tss_sel, 34198c2ecf20Sopenharmony_ci old_tss_base, &next_tss_desc); 34208c2ecf20Sopenharmony_ci if (ret != X86EMUL_CONTINUE) 34218c2ecf20Sopenharmony_ci return ret; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci if (reason == TASK_SWITCH_CALL || reason == TASK_SWITCH_GATE) 34248c2ecf20Sopenharmony_ci ctxt->eflags = ctxt->eflags | X86_EFLAGS_NT; 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci if (reason != TASK_SWITCH_IRET) { 34278c2ecf20Sopenharmony_ci next_tss_desc.type |= (1 << 1); /* set busy flag */ 34288c2ecf20Sopenharmony_ci write_segment_descriptor(ctxt, tss_selector, &next_tss_desc); 34298c2ecf20Sopenharmony_ci } 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci ops->set_cr(ctxt, 0, ops->get_cr(ctxt, 0) | X86_CR0_TS); 34328c2ecf20Sopenharmony_ci ops->set_segment(ctxt, tss_selector, &next_tss_desc, 0, VCPU_SREG_TR); 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_ci if (has_error_code) { 34358c2ecf20Sopenharmony_ci ctxt->op_bytes = ctxt->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; 34368c2ecf20Sopenharmony_ci ctxt->lock_prefix = 0; 34378c2ecf20Sopenharmony_ci ctxt->src.val = (unsigned long) error_code; 34388c2ecf20Sopenharmony_ci ret = em_push(ctxt); 34398c2ecf20Sopenharmony_ci } 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci ops->get_dr(ctxt, 7, &dr7); 34428c2ecf20Sopenharmony_ci ops->set_dr(ctxt, 7, dr7 & ~(DR_LOCAL_ENABLE_MASK | DR_LOCAL_SLOWDOWN)); 34438c2ecf20Sopenharmony_ci 34448c2ecf20Sopenharmony_ci return ret; 34458c2ecf20Sopenharmony_ci} 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ciint emulator_task_switch(struct x86_emulate_ctxt *ctxt, 34488c2ecf20Sopenharmony_ci u16 tss_selector, int idt_index, int reason, 34498c2ecf20Sopenharmony_ci bool has_error_code, u32 error_code) 34508c2ecf20Sopenharmony_ci{ 34518c2ecf20Sopenharmony_ci int rc; 34528c2ecf20Sopenharmony_ci 34538c2ecf20Sopenharmony_ci invalidate_registers(ctxt); 34548c2ecf20Sopenharmony_ci ctxt->_eip = ctxt->eip; 34558c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason, 34588c2ecf20Sopenharmony_ci has_error_code, error_code); 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) { 34618c2ecf20Sopenharmony_ci ctxt->eip = ctxt->_eip; 34628c2ecf20Sopenharmony_ci writeback_registers(ctxt); 34638c2ecf20Sopenharmony_ci } 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; 34668c2ecf20Sopenharmony_ci} 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_cistatic void string_addr_inc(struct x86_emulate_ctxt *ctxt, int reg, 34698c2ecf20Sopenharmony_ci struct operand *op) 34708c2ecf20Sopenharmony_ci{ 34718c2ecf20Sopenharmony_ci int df = (ctxt->eflags & X86_EFLAGS_DF) ? -op->count : op->count; 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci register_address_increment(ctxt, reg, df * op->bytes); 34748c2ecf20Sopenharmony_ci op->addr.mem.ea = register_address(ctxt, reg); 34758c2ecf20Sopenharmony_ci} 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_cistatic int em_das(struct x86_emulate_ctxt *ctxt) 34788c2ecf20Sopenharmony_ci{ 34798c2ecf20Sopenharmony_ci u8 al, old_al; 34808c2ecf20Sopenharmony_ci bool af, cf, old_cf; 34818c2ecf20Sopenharmony_ci 34828c2ecf20Sopenharmony_ci cf = ctxt->eflags & X86_EFLAGS_CF; 34838c2ecf20Sopenharmony_ci al = ctxt->dst.val; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci old_al = al; 34868c2ecf20Sopenharmony_ci old_cf = cf; 34878c2ecf20Sopenharmony_ci cf = false; 34888c2ecf20Sopenharmony_ci af = ctxt->eflags & X86_EFLAGS_AF; 34898c2ecf20Sopenharmony_ci if ((al & 0x0f) > 9 || af) { 34908c2ecf20Sopenharmony_ci al -= 6; 34918c2ecf20Sopenharmony_ci cf = old_cf | (al >= 250); 34928c2ecf20Sopenharmony_ci af = true; 34938c2ecf20Sopenharmony_ci } else { 34948c2ecf20Sopenharmony_ci af = false; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci if (old_al > 0x99 || old_cf) { 34978c2ecf20Sopenharmony_ci al -= 0x60; 34988c2ecf20Sopenharmony_ci cf = true; 34998c2ecf20Sopenharmony_ci } 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci ctxt->dst.val = al; 35028c2ecf20Sopenharmony_ci /* Set PF, ZF, SF */ 35038c2ecf20Sopenharmony_ci ctxt->src.type = OP_IMM; 35048c2ecf20Sopenharmony_ci ctxt->src.val = 0; 35058c2ecf20Sopenharmony_ci ctxt->src.bytes = 1; 35068c2ecf20Sopenharmony_ci fastop(ctxt, em_or); 35078c2ecf20Sopenharmony_ci ctxt->eflags &= ~(X86_EFLAGS_AF | X86_EFLAGS_CF); 35088c2ecf20Sopenharmony_ci if (cf) 35098c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_CF; 35108c2ecf20Sopenharmony_ci if (af) 35118c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_AF; 35128c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 35138c2ecf20Sopenharmony_ci} 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_cistatic int em_aam(struct x86_emulate_ctxt *ctxt) 35168c2ecf20Sopenharmony_ci{ 35178c2ecf20Sopenharmony_ci u8 al, ah; 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci if (ctxt->src.val == 0) 35208c2ecf20Sopenharmony_ci return emulate_de(ctxt); 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci al = ctxt->dst.val & 0xff; 35238c2ecf20Sopenharmony_ci ah = al / ctxt->src.val; 35248c2ecf20Sopenharmony_ci al %= ctxt->src.val; 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci ctxt->dst.val = (ctxt->dst.val & 0xffff0000) | al | (ah << 8); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci /* Set PF, ZF, SF */ 35298c2ecf20Sopenharmony_ci ctxt->src.type = OP_IMM; 35308c2ecf20Sopenharmony_ci ctxt->src.val = 0; 35318c2ecf20Sopenharmony_ci ctxt->src.bytes = 1; 35328c2ecf20Sopenharmony_ci fastop(ctxt, em_or); 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 35358c2ecf20Sopenharmony_ci} 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_cistatic int em_aad(struct x86_emulate_ctxt *ctxt) 35388c2ecf20Sopenharmony_ci{ 35398c2ecf20Sopenharmony_ci u8 al = ctxt->dst.val & 0xff; 35408c2ecf20Sopenharmony_ci u8 ah = (ctxt->dst.val >> 8) & 0xff; 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci al = (al + (ah * ctxt->src.val)) & 0xff; 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci ctxt->dst.val = (ctxt->dst.val & 0xffff0000) | al; 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci /* Set PF, ZF, SF */ 35478c2ecf20Sopenharmony_ci ctxt->src.type = OP_IMM; 35488c2ecf20Sopenharmony_ci ctxt->src.val = 0; 35498c2ecf20Sopenharmony_ci ctxt->src.bytes = 1; 35508c2ecf20Sopenharmony_ci fastop(ctxt, em_or); 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_cistatic int em_call(struct x86_emulate_ctxt *ctxt) 35568c2ecf20Sopenharmony_ci{ 35578c2ecf20Sopenharmony_ci int rc; 35588c2ecf20Sopenharmony_ci long rel = ctxt->src.val; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci ctxt->src.val = (unsigned long)ctxt->_eip; 35618c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, rel); 35628c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 35638c2ecf20Sopenharmony_ci return rc; 35648c2ecf20Sopenharmony_ci return em_push(ctxt); 35658c2ecf20Sopenharmony_ci} 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_cistatic int em_call_far(struct x86_emulate_ctxt *ctxt) 35688c2ecf20Sopenharmony_ci{ 35698c2ecf20Sopenharmony_ci u16 sel, old_cs; 35708c2ecf20Sopenharmony_ci ulong old_eip; 35718c2ecf20Sopenharmony_ci int rc; 35728c2ecf20Sopenharmony_ci struct desc_struct old_desc, new_desc; 35738c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 35748c2ecf20Sopenharmony_ci int cpl = ctxt->ops->cpl(ctxt); 35758c2ecf20Sopenharmony_ci enum x86emul_mode prev_mode = ctxt->mode; 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci old_eip = ctxt->_eip; 35788c2ecf20Sopenharmony_ci ops->get_segment(ctxt, &old_cs, &old_desc, NULL, VCPU_SREG_CS); 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2); 35818c2ecf20Sopenharmony_ci rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl, 35828c2ecf20Sopenharmony_ci X86_TRANSFER_CALL_JMP, &new_desc); 35838c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 35848c2ecf20Sopenharmony_ci return rc; 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci rc = assign_eip_far(ctxt, ctxt->src.val); 35878c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 35888c2ecf20Sopenharmony_ci goto fail; 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci ctxt->src.val = old_cs; 35918c2ecf20Sopenharmony_ci rc = em_push(ctxt); 35928c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 35938c2ecf20Sopenharmony_ci goto fail; 35948c2ecf20Sopenharmony_ci 35958c2ecf20Sopenharmony_ci ctxt->src.val = old_eip; 35968c2ecf20Sopenharmony_ci rc = em_push(ctxt); 35978c2ecf20Sopenharmony_ci /* If we failed, we tainted the memory, but the very least we should 35988c2ecf20Sopenharmony_ci restore cs */ 35998c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) { 36008c2ecf20Sopenharmony_ci pr_warn_once("faulting far call emulation tainted memory\n"); 36018c2ecf20Sopenharmony_ci goto fail; 36028c2ecf20Sopenharmony_ci } 36038c2ecf20Sopenharmony_ci return rc; 36048c2ecf20Sopenharmony_cifail: 36058c2ecf20Sopenharmony_ci ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS); 36068c2ecf20Sopenharmony_ci ctxt->mode = prev_mode; 36078c2ecf20Sopenharmony_ci return rc; 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci} 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_cistatic int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) 36128c2ecf20Sopenharmony_ci{ 36138c2ecf20Sopenharmony_ci int rc; 36148c2ecf20Sopenharmony_ci unsigned long eip; 36158c2ecf20Sopenharmony_ci 36168c2ecf20Sopenharmony_ci rc = emulate_pop(ctxt, &eip, ctxt->op_bytes); 36178c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 36188c2ecf20Sopenharmony_ci return rc; 36198c2ecf20Sopenharmony_ci rc = assign_eip_near(ctxt, eip); 36208c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 36218c2ecf20Sopenharmony_ci return rc; 36228c2ecf20Sopenharmony_ci rsp_increment(ctxt, ctxt->src.val); 36238c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36248c2ecf20Sopenharmony_ci} 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_cistatic int em_xchg(struct x86_emulate_ctxt *ctxt) 36278c2ecf20Sopenharmony_ci{ 36288c2ecf20Sopenharmony_ci /* Write back the register source. */ 36298c2ecf20Sopenharmony_ci ctxt->src.val = ctxt->dst.val; 36308c2ecf20Sopenharmony_ci write_register_operand(&ctxt->src); 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci /* Write back the memory destination with implicit LOCK prefix. */ 36338c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src.orig_val; 36348c2ecf20Sopenharmony_ci ctxt->lock_prefix = 1; 36358c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36368c2ecf20Sopenharmony_ci} 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_cistatic int em_imul_3op(struct x86_emulate_ctxt *ctxt) 36398c2ecf20Sopenharmony_ci{ 36408c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src2.val; 36418c2ecf20Sopenharmony_ci return fastop(ctxt, em_imul); 36428c2ecf20Sopenharmony_ci} 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_cistatic int em_cwd(struct x86_emulate_ctxt *ctxt) 36458c2ecf20Sopenharmony_ci{ 36468c2ecf20Sopenharmony_ci ctxt->dst.type = OP_REG; 36478c2ecf20Sopenharmony_ci ctxt->dst.bytes = ctxt->src.bytes; 36488c2ecf20Sopenharmony_ci ctxt->dst.addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX); 36498c2ecf20Sopenharmony_ci ctxt->dst.val = ~((ctxt->src.val >> (ctxt->src.bytes * 8 - 1)) - 1); 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36528c2ecf20Sopenharmony_ci} 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_cistatic int em_rdpid(struct x86_emulate_ctxt *ctxt) 36558c2ecf20Sopenharmony_ci{ 36568c2ecf20Sopenharmony_ci u64 tsc_aux = 0; 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci if (!ctxt->ops->guest_has_rdpid(ctxt)) 36598c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_TSC_AUX, &tsc_aux); 36628c2ecf20Sopenharmony_ci ctxt->dst.val = tsc_aux; 36638c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36648c2ecf20Sopenharmony_ci} 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_cistatic int em_rdtsc(struct x86_emulate_ctxt *ctxt) 36678c2ecf20Sopenharmony_ci{ 36688c2ecf20Sopenharmony_ci u64 tsc = 0; 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_IA32_TSC, &tsc); 36718c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = (u32)tsc; 36728c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = tsc >> 32; 36738c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36748c2ecf20Sopenharmony_ci} 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_cistatic int em_rdpmc(struct x86_emulate_ctxt *ctxt) 36778c2ecf20Sopenharmony_ci{ 36788c2ecf20Sopenharmony_ci u64 pmc; 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci if (ctxt->ops->read_pmc(ctxt, reg_read(ctxt, VCPU_REGS_RCX), &pmc)) 36818c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 36828c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = (u32)pmc; 36838c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = pmc >> 32; 36848c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36858c2ecf20Sopenharmony_ci} 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_cistatic int em_mov(struct x86_emulate_ctxt *ctxt) 36888c2ecf20Sopenharmony_ci{ 36898c2ecf20Sopenharmony_ci memcpy(ctxt->dst.valptr, ctxt->src.valptr, sizeof(ctxt->src.valptr)); 36908c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 36918c2ecf20Sopenharmony_ci} 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_cistatic int em_movbe(struct x86_emulate_ctxt *ctxt) 36948c2ecf20Sopenharmony_ci{ 36958c2ecf20Sopenharmony_ci u16 tmp; 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci if (!ctxt->ops->guest_has_movbe(ctxt)) 36988c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 36998c2ecf20Sopenharmony_ci 37008c2ecf20Sopenharmony_ci switch (ctxt->op_bytes) { 37018c2ecf20Sopenharmony_ci case 2: 37028c2ecf20Sopenharmony_ci /* 37038c2ecf20Sopenharmony_ci * From MOVBE definition: "...When the operand size is 16 bits, 37048c2ecf20Sopenharmony_ci * the upper word of the destination register remains unchanged 37058c2ecf20Sopenharmony_ci * ..." 37068c2ecf20Sopenharmony_ci * 37078c2ecf20Sopenharmony_ci * Both casting ->valptr and ->val to u16 breaks strict aliasing 37088c2ecf20Sopenharmony_ci * rules so we have to do the operation almost per hand. 37098c2ecf20Sopenharmony_ci */ 37108c2ecf20Sopenharmony_ci tmp = (u16)ctxt->src.val; 37118c2ecf20Sopenharmony_ci ctxt->dst.val &= ~0xffffUL; 37128c2ecf20Sopenharmony_ci ctxt->dst.val |= (unsigned long)swab16(tmp); 37138c2ecf20Sopenharmony_ci break; 37148c2ecf20Sopenharmony_ci case 4: 37158c2ecf20Sopenharmony_ci ctxt->dst.val = swab32((u32)ctxt->src.val); 37168c2ecf20Sopenharmony_ci break; 37178c2ecf20Sopenharmony_ci case 8: 37188c2ecf20Sopenharmony_ci ctxt->dst.val = swab64(ctxt->src.val); 37198c2ecf20Sopenharmony_ci break; 37208c2ecf20Sopenharmony_ci default: 37218c2ecf20Sopenharmony_ci BUG(); 37228c2ecf20Sopenharmony_ci } 37238c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 37248c2ecf20Sopenharmony_ci} 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_cistatic int em_cr_write(struct x86_emulate_ctxt *ctxt) 37278c2ecf20Sopenharmony_ci{ 37288c2ecf20Sopenharmony_ci int cr_num = ctxt->modrm_reg; 37298c2ecf20Sopenharmony_ci int r; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci if (ctxt->ops->set_cr(ctxt, cr_num, ctxt->src.val)) 37328c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci /* Disable writeback. */ 37358c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci if (cr_num == 0) { 37388c2ecf20Sopenharmony_ci /* 37398c2ecf20Sopenharmony_ci * CR0 write might have updated CR0.PE and/or CR0.PG 37408c2ecf20Sopenharmony_ci * which can affect the cpu's execution mode. 37418c2ecf20Sopenharmony_ci */ 37428c2ecf20Sopenharmony_ci r = emulator_recalc_and_set_mode(ctxt); 37438c2ecf20Sopenharmony_ci if (r != X86EMUL_CONTINUE) 37448c2ecf20Sopenharmony_ci return r; 37458c2ecf20Sopenharmony_ci } 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 37488c2ecf20Sopenharmony_ci} 37498c2ecf20Sopenharmony_ci 37508c2ecf20Sopenharmony_cistatic int em_dr_write(struct x86_emulate_ctxt *ctxt) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci unsigned long val; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 37558c2ecf20Sopenharmony_ci val = ctxt->src.val & ~0ULL; 37568c2ecf20Sopenharmony_ci else 37578c2ecf20Sopenharmony_ci val = ctxt->src.val & ~0U; 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci /* #UD condition is already handled. */ 37608c2ecf20Sopenharmony_ci if (ctxt->ops->set_dr(ctxt, ctxt->modrm_reg, val) < 0) 37618c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci /* Disable writeback. */ 37648c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 37658c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 37668c2ecf20Sopenharmony_ci} 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_cistatic int em_wrmsr(struct x86_emulate_ctxt *ctxt) 37698c2ecf20Sopenharmony_ci{ 37708c2ecf20Sopenharmony_ci u64 msr_index = reg_read(ctxt, VCPU_REGS_RCX); 37718c2ecf20Sopenharmony_ci u64 msr_data; 37728c2ecf20Sopenharmony_ci int r; 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci msr_data = (u32)reg_read(ctxt, VCPU_REGS_RAX) 37758c2ecf20Sopenharmony_ci | ((u64)reg_read(ctxt, VCPU_REGS_RDX) << 32); 37768c2ecf20Sopenharmony_ci r = ctxt->ops->set_msr(ctxt, msr_index, msr_data); 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci if (r == X86EMUL_IO_NEEDED) 37798c2ecf20Sopenharmony_ci return r; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci if (r > 0) 37828c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci return r < 0 ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE; 37858c2ecf20Sopenharmony_ci} 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_cistatic int em_rdmsr(struct x86_emulate_ctxt *ctxt) 37888c2ecf20Sopenharmony_ci{ 37898c2ecf20Sopenharmony_ci u64 msr_index = reg_read(ctxt, VCPU_REGS_RCX); 37908c2ecf20Sopenharmony_ci u64 msr_data; 37918c2ecf20Sopenharmony_ci int r; 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci r = ctxt->ops->get_msr(ctxt, msr_index, &msr_data); 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci if (r == X86EMUL_IO_NEEDED) 37968c2ecf20Sopenharmony_ci return r; 37978c2ecf20Sopenharmony_ci 37988c2ecf20Sopenharmony_ci if (r) 37998c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = (u32)msr_data; 38028c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = msr_data >> 32; 38038c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 38048c2ecf20Sopenharmony_ci} 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_cistatic int em_store_sreg(struct x86_emulate_ctxt *ctxt, int segment) 38078c2ecf20Sopenharmony_ci{ 38088c2ecf20Sopenharmony_ci if (segment > VCPU_SREG_GS && 38098c2ecf20Sopenharmony_ci (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_UMIP) && 38108c2ecf20Sopenharmony_ci ctxt->ops->cpl(ctxt) > 0) 38118c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci ctxt->dst.val = get_segment_selector(ctxt, segment); 38148c2ecf20Sopenharmony_ci if (ctxt->dst.bytes == 4 && ctxt->dst.type == OP_MEM) 38158c2ecf20Sopenharmony_ci ctxt->dst.bytes = 2; 38168c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 38178c2ecf20Sopenharmony_ci} 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_cistatic int em_mov_rm_sreg(struct x86_emulate_ctxt *ctxt) 38208c2ecf20Sopenharmony_ci{ 38218c2ecf20Sopenharmony_ci if (ctxt->modrm_reg > VCPU_SREG_GS) 38228c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci return em_store_sreg(ctxt, ctxt->modrm_reg); 38258c2ecf20Sopenharmony_ci} 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_cistatic int em_mov_sreg_rm(struct x86_emulate_ctxt *ctxt) 38288c2ecf20Sopenharmony_ci{ 38298c2ecf20Sopenharmony_ci u16 sel = ctxt->src.val; 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci if (ctxt->modrm_reg == VCPU_SREG_CS || ctxt->modrm_reg > VCPU_SREG_GS) 38328c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci if (ctxt->modrm_reg == VCPU_SREG_SS) 38358c2ecf20Sopenharmony_ci ctxt->interruptibility = KVM_X86_SHADOW_INT_MOV_SS; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci /* Disable writeback. */ 38388c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 38398c2ecf20Sopenharmony_ci return load_segment_descriptor(ctxt, sel, ctxt->modrm_reg); 38408c2ecf20Sopenharmony_ci} 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_cistatic int em_sldt(struct x86_emulate_ctxt *ctxt) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci return em_store_sreg(ctxt, VCPU_SREG_LDTR); 38458c2ecf20Sopenharmony_ci} 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_cistatic int em_lldt(struct x86_emulate_ctxt *ctxt) 38488c2ecf20Sopenharmony_ci{ 38498c2ecf20Sopenharmony_ci u16 sel = ctxt->src.val; 38508c2ecf20Sopenharmony_ci 38518c2ecf20Sopenharmony_ci /* Disable writeback. */ 38528c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 38538c2ecf20Sopenharmony_ci return load_segment_descriptor(ctxt, sel, VCPU_SREG_LDTR); 38548c2ecf20Sopenharmony_ci} 38558c2ecf20Sopenharmony_ci 38568c2ecf20Sopenharmony_cistatic int em_str(struct x86_emulate_ctxt *ctxt) 38578c2ecf20Sopenharmony_ci{ 38588c2ecf20Sopenharmony_ci return em_store_sreg(ctxt, VCPU_SREG_TR); 38598c2ecf20Sopenharmony_ci} 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_cistatic int em_ltr(struct x86_emulate_ctxt *ctxt) 38628c2ecf20Sopenharmony_ci{ 38638c2ecf20Sopenharmony_ci u16 sel = ctxt->src.val; 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci /* Disable writeback. */ 38668c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 38678c2ecf20Sopenharmony_ci return load_segment_descriptor(ctxt, sel, VCPU_SREG_TR); 38688c2ecf20Sopenharmony_ci} 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_cistatic int em_invlpg(struct x86_emulate_ctxt *ctxt) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci int rc; 38738c2ecf20Sopenharmony_ci ulong linear; 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_ci rc = linearize(ctxt, ctxt->src.addr.mem, 1, false, &linear); 38768c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) 38778c2ecf20Sopenharmony_ci ctxt->ops->invlpg(ctxt, linear); 38788c2ecf20Sopenharmony_ci /* Disable writeback. */ 38798c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 38808c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 38818c2ecf20Sopenharmony_ci} 38828c2ecf20Sopenharmony_ci 38838c2ecf20Sopenharmony_cistatic int em_clts(struct x86_emulate_ctxt *ctxt) 38848c2ecf20Sopenharmony_ci{ 38858c2ecf20Sopenharmony_ci ulong cr0; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci cr0 = ctxt->ops->get_cr(ctxt, 0); 38888c2ecf20Sopenharmony_ci cr0 &= ~X86_CR0_TS; 38898c2ecf20Sopenharmony_ci ctxt->ops->set_cr(ctxt, 0, cr0); 38908c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 38918c2ecf20Sopenharmony_ci} 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_cistatic int em_hypercall(struct x86_emulate_ctxt *ctxt) 38948c2ecf20Sopenharmony_ci{ 38958c2ecf20Sopenharmony_ci int rc = ctxt->ops->fix_hypercall(ctxt); 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 38988c2ecf20Sopenharmony_ci return rc; 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci /* Let the processor re-execute the fixed hypercall */ 39018c2ecf20Sopenharmony_ci ctxt->_eip = ctxt->eip; 39028c2ecf20Sopenharmony_ci /* Disable writeback. */ 39038c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 39048c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 39058c2ecf20Sopenharmony_ci} 39068c2ecf20Sopenharmony_ci 39078c2ecf20Sopenharmony_cistatic int emulate_store_desc_ptr(struct x86_emulate_ctxt *ctxt, 39088c2ecf20Sopenharmony_ci void (*get)(struct x86_emulate_ctxt *ctxt, 39098c2ecf20Sopenharmony_ci struct desc_ptr *ptr)) 39108c2ecf20Sopenharmony_ci{ 39118c2ecf20Sopenharmony_ci struct desc_ptr desc_ptr; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci if ((ctxt->ops->get_cr(ctxt, 4) & X86_CR4_UMIP) && 39148c2ecf20Sopenharmony_ci ctxt->ops->cpl(ctxt) > 0) 39158c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 39188c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 39198c2ecf20Sopenharmony_ci get(ctxt, &desc_ptr); 39208c2ecf20Sopenharmony_ci if (ctxt->op_bytes == 2) { 39218c2ecf20Sopenharmony_ci ctxt->op_bytes = 4; 39228c2ecf20Sopenharmony_ci desc_ptr.address &= 0x00ffffff; 39238c2ecf20Sopenharmony_ci } 39248c2ecf20Sopenharmony_ci /* Disable writeback. */ 39258c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 39268c2ecf20Sopenharmony_ci return segmented_write_std(ctxt, ctxt->dst.addr.mem, 39278c2ecf20Sopenharmony_ci &desc_ptr, 2 + ctxt->op_bytes); 39288c2ecf20Sopenharmony_ci} 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_cistatic int em_sgdt(struct x86_emulate_ctxt *ctxt) 39318c2ecf20Sopenharmony_ci{ 39328c2ecf20Sopenharmony_ci return emulate_store_desc_ptr(ctxt, ctxt->ops->get_gdt); 39338c2ecf20Sopenharmony_ci} 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_cistatic int em_sidt(struct x86_emulate_ctxt *ctxt) 39368c2ecf20Sopenharmony_ci{ 39378c2ecf20Sopenharmony_ci return emulate_store_desc_ptr(ctxt, ctxt->ops->get_idt); 39388c2ecf20Sopenharmony_ci} 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_cistatic int em_lgdt_lidt(struct x86_emulate_ctxt *ctxt, bool lgdt) 39418c2ecf20Sopenharmony_ci{ 39428c2ecf20Sopenharmony_ci struct desc_ptr desc_ptr; 39438c2ecf20Sopenharmony_ci int rc; 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 39468c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 39478c2ecf20Sopenharmony_ci rc = read_descriptor(ctxt, ctxt->src.addr.mem, 39488c2ecf20Sopenharmony_ci &desc_ptr.size, &desc_ptr.address, 39498c2ecf20Sopenharmony_ci ctxt->op_bytes); 39508c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 39518c2ecf20Sopenharmony_ci return rc; 39528c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64 && 39538c2ecf20Sopenharmony_ci emul_is_noncanonical_address(desc_ptr.address, ctxt)) 39548c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 39558c2ecf20Sopenharmony_ci if (lgdt) 39568c2ecf20Sopenharmony_ci ctxt->ops->set_gdt(ctxt, &desc_ptr); 39578c2ecf20Sopenharmony_ci else 39588c2ecf20Sopenharmony_ci ctxt->ops->set_idt(ctxt, &desc_ptr); 39598c2ecf20Sopenharmony_ci /* Disable writeback. */ 39608c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 39618c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 39628c2ecf20Sopenharmony_ci} 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_cistatic int em_lgdt(struct x86_emulate_ctxt *ctxt) 39658c2ecf20Sopenharmony_ci{ 39668c2ecf20Sopenharmony_ci return em_lgdt_lidt(ctxt, true); 39678c2ecf20Sopenharmony_ci} 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_cistatic int em_lidt(struct x86_emulate_ctxt *ctxt) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci return em_lgdt_lidt(ctxt, false); 39728c2ecf20Sopenharmony_ci} 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_cistatic int em_smsw(struct x86_emulate_ctxt *ctxt) 39758c2ecf20Sopenharmony_ci{ 39768c2ecf20Sopenharmony_ci if ((ctxt->ops->get_cr(ctxt, 4) & X86_CR4_UMIP) && 39778c2ecf20Sopenharmony_ci ctxt->ops->cpl(ctxt) > 0) 39788c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 39798c2ecf20Sopenharmony_ci 39808c2ecf20Sopenharmony_ci if (ctxt->dst.type == OP_MEM) 39818c2ecf20Sopenharmony_ci ctxt->dst.bytes = 2; 39828c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->ops->get_cr(ctxt, 0); 39838c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 39848c2ecf20Sopenharmony_ci} 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_cistatic int em_lmsw(struct x86_emulate_ctxt *ctxt) 39878c2ecf20Sopenharmony_ci{ 39888c2ecf20Sopenharmony_ci ctxt->ops->set_cr(ctxt, 0, (ctxt->ops->get_cr(ctxt, 0) & ~0x0eul) 39898c2ecf20Sopenharmony_ci | (ctxt->src.val & 0x0f)); 39908c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 39918c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 39928c2ecf20Sopenharmony_ci} 39938c2ecf20Sopenharmony_ci 39948c2ecf20Sopenharmony_cistatic int em_loop(struct x86_emulate_ctxt *ctxt) 39958c2ecf20Sopenharmony_ci{ 39968c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 39978c2ecf20Sopenharmony_ci 39988c2ecf20Sopenharmony_ci register_address_increment(ctxt, VCPU_REGS_RCX, -1); 39998c2ecf20Sopenharmony_ci if ((address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) != 0) && 40008c2ecf20Sopenharmony_ci (ctxt->b == 0xe2 || test_cc(ctxt->b ^ 0x5, ctxt->eflags))) 40018c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, ctxt->src.val); 40028c2ecf20Sopenharmony_ci 40038c2ecf20Sopenharmony_ci return rc; 40048c2ecf20Sopenharmony_ci} 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_cistatic int em_jcxz(struct x86_emulate_ctxt *ctxt) 40078c2ecf20Sopenharmony_ci{ 40088c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) 40118c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, ctxt->src.val); 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci return rc; 40148c2ecf20Sopenharmony_ci} 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_cistatic int em_in(struct x86_emulate_ctxt *ctxt) 40178c2ecf20Sopenharmony_ci{ 40188c2ecf20Sopenharmony_ci if (!pio_in_emulated(ctxt, ctxt->dst.bytes, ctxt->src.val, 40198c2ecf20Sopenharmony_ci &ctxt->dst.val)) 40208c2ecf20Sopenharmony_ci return X86EMUL_IO_NEEDED; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40238c2ecf20Sopenharmony_ci} 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_cistatic int em_out(struct x86_emulate_ctxt *ctxt) 40268c2ecf20Sopenharmony_ci{ 40278c2ecf20Sopenharmony_ci ctxt->ops->pio_out_emulated(ctxt, ctxt->src.bytes, ctxt->dst.val, 40288c2ecf20Sopenharmony_ci &ctxt->src.val, 1); 40298c2ecf20Sopenharmony_ci /* Disable writeback. */ 40308c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 40318c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40328c2ecf20Sopenharmony_ci} 40338c2ecf20Sopenharmony_ci 40348c2ecf20Sopenharmony_cistatic int em_cli(struct x86_emulate_ctxt *ctxt) 40358c2ecf20Sopenharmony_ci{ 40368c2ecf20Sopenharmony_ci if (emulator_bad_iopl(ctxt)) 40378c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_IF; 40408c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40418c2ecf20Sopenharmony_ci} 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_cistatic int em_sti(struct x86_emulate_ctxt *ctxt) 40448c2ecf20Sopenharmony_ci{ 40458c2ecf20Sopenharmony_ci if (emulator_bad_iopl(ctxt)) 40468c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci ctxt->interruptibility = KVM_X86_SHADOW_INT_STI; 40498c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_IF; 40508c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40518c2ecf20Sopenharmony_ci} 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_cistatic int em_cpuid(struct x86_emulate_ctxt *ctxt) 40548c2ecf20Sopenharmony_ci{ 40558c2ecf20Sopenharmony_ci u32 eax, ebx, ecx, edx; 40568c2ecf20Sopenharmony_ci u64 msr = 0; 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_MISC_FEATURES_ENABLES, &msr); 40598c2ecf20Sopenharmony_ci if (msr & MSR_MISC_FEATURES_ENABLES_CPUID_FAULT && 40608c2ecf20Sopenharmony_ci ctxt->ops->cpl(ctxt)) { 40618c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 40628c2ecf20Sopenharmony_ci } 40638c2ecf20Sopenharmony_ci 40648c2ecf20Sopenharmony_ci eax = reg_read(ctxt, VCPU_REGS_RAX); 40658c2ecf20Sopenharmony_ci ecx = reg_read(ctxt, VCPU_REGS_RCX); 40668c2ecf20Sopenharmony_ci ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, false); 40678c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RAX) = eax; 40688c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RBX) = ebx; 40698c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RCX) = ecx; 40708c2ecf20Sopenharmony_ci *reg_write(ctxt, VCPU_REGS_RDX) = edx; 40718c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40728c2ecf20Sopenharmony_ci} 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_cistatic int em_sahf(struct x86_emulate_ctxt *ctxt) 40758c2ecf20Sopenharmony_ci{ 40768c2ecf20Sopenharmony_ci u32 flags; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci flags = X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | 40798c2ecf20Sopenharmony_ci X86_EFLAGS_SF; 40808c2ecf20Sopenharmony_ci flags &= *reg_rmw(ctxt, VCPU_REGS_RAX) >> 8; 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci ctxt->eflags &= ~0xffUL; 40838c2ecf20Sopenharmony_ci ctxt->eflags |= flags | X86_EFLAGS_FIXED; 40848c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40858c2ecf20Sopenharmony_ci} 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_cistatic int em_lahf(struct x86_emulate_ctxt *ctxt) 40888c2ecf20Sopenharmony_ci{ 40898c2ecf20Sopenharmony_ci *reg_rmw(ctxt, VCPU_REGS_RAX) &= ~0xff00UL; 40908c2ecf20Sopenharmony_ci *reg_rmw(ctxt, VCPU_REGS_RAX) |= (ctxt->eflags & 0xff) << 8; 40918c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 40928c2ecf20Sopenharmony_ci} 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_cistatic int em_bswap(struct x86_emulate_ctxt *ctxt) 40958c2ecf20Sopenharmony_ci{ 40968c2ecf20Sopenharmony_ci switch (ctxt->op_bytes) { 40978c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 40988c2ecf20Sopenharmony_ci case 8: 40998c2ecf20Sopenharmony_ci asm("bswap %0" : "+r"(ctxt->dst.val)); 41008c2ecf20Sopenharmony_ci break; 41018c2ecf20Sopenharmony_ci#endif 41028c2ecf20Sopenharmony_ci default: 41038c2ecf20Sopenharmony_ci asm("bswap %0" : "+r"(*(u32 *)&ctxt->dst.val)); 41048c2ecf20Sopenharmony_ci break; 41058c2ecf20Sopenharmony_ci } 41068c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 41078c2ecf20Sopenharmony_ci} 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_cistatic int em_clflush(struct x86_emulate_ctxt *ctxt) 41108c2ecf20Sopenharmony_ci{ 41118c2ecf20Sopenharmony_ci /* emulating clflush regardless of cpuid */ 41128c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 41138c2ecf20Sopenharmony_ci} 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_cistatic int em_clflushopt(struct x86_emulate_ctxt *ctxt) 41168c2ecf20Sopenharmony_ci{ 41178c2ecf20Sopenharmony_ci /* emulating clflushopt regardless of cpuid */ 41188c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 41198c2ecf20Sopenharmony_ci} 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_cistatic int em_movsxd(struct x86_emulate_ctxt *ctxt) 41228c2ecf20Sopenharmony_ci{ 41238c2ecf20Sopenharmony_ci ctxt->dst.val = (s32) ctxt->src.val; 41248c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 41258c2ecf20Sopenharmony_ci} 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_cistatic int check_fxsr(struct x86_emulate_ctxt *ctxt) 41288c2ecf20Sopenharmony_ci{ 41298c2ecf20Sopenharmony_ci if (!ctxt->ops->guest_has_fxsr(ctxt)) 41308c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM)) 41338c2ecf20Sopenharmony_ci return emulate_nm(ctxt); 41348c2ecf20Sopenharmony_ci 41358c2ecf20Sopenharmony_ci /* 41368c2ecf20Sopenharmony_ci * Don't emulate a case that should never be hit, instead of working 41378c2ecf20Sopenharmony_ci * around a lack of fxsave64/fxrstor64 on old compilers. 41388c2ecf20Sopenharmony_ci */ 41398c2ecf20Sopenharmony_ci if (ctxt->mode >= X86EMUL_MODE_PROT64) 41408c2ecf20Sopenharmony_ci return X86EMUL_UNHANDLEABLE; 41418c2ecf20Sopenharmony_ci 41428c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 41438c2ecf20Sopenharmony_ci} 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci/* 41468c2ecf20Sopenharmony_ci * Hardware doesn't save and restore XMM 0-7 without CR4.OSFXSR, but does save 41478c2ecf20Sopenharmony_ci * and restore MXCSR. 41488c2ecf20Sopenharmony_ci */ 41498c2ecf20Sopenharmony_cistatic size_t __fxstate_size(int nregs) 41508c2ecf20Sopenharmony_ci{ 41518c2ecf20Sopenharmony_ci return offsetof(struct fxregs_state, xmm_space[0]) + nregs * 16; 41528c2ecf20Sopenharmony_ci} 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_cistatic inline size_t fxstate_size(struct x86_emulate_ctxt *ctxt) 41558c2ecf20Sopenharmony_ci{ 41568c2ecf20Sopenharmony_ci bool cr4_osfxsr; 41578c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 41588c2ecf20Sopenharmony_ci return __fxstate_size(16); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci cr4_osfxsr = ctxt->ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR; 41618c2ecf20Sopenharmony_ci return __fxstate_size(cr4_osfxsr ? 8 : 0); 41628c2ecf20Sopenharmony_ci} 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci/* 41658c2ecf20Sopenharmony_ci * FXSAVE and FXRSTOR have 4 different formats depending on execution mode, 41668c2ecf20Sopenharmony_ci * 1) 16 bit mode 41678c2ecf20Sopenharmony_ci * 2) 32 bit mode 41688c2ecf20Sopenharmony_ci * - like (1), but FIP and FDP (foo) are only 16 bit. At least Intel CPUs 41698c2ecf20Sopenharmony_ci * preserve whole 32 bit values, though, so (1) and (2) are the same wrt. 41708c2ecf20Sopenharmony_ci * save and restore 41718c2ecf20Sopenharmony_ci * 3) 64-bit mode with REX.W prefix 41728c2ecf20Sopenharmony_ci * - like (2), but XMM 8-15 are being saved and restored 41738c2ecf20Sopenharmony_ci * 4) 64-bit mode without REX.W prefix 41748c2ecf20Sopenharmony_ci * - like (3), but FIP and FDP are 64 bit 41758c2ecf20Sopenharmony_ci * 41768c2ecf20Sopenharmony_ci * Emulation uses (3) for (1) and (2) and preserves XMM 8-15 to reach the 41778c2ecf20Sopenharmony_ci * desired result. (4) is not emulated. 41788c2ecf20Sopenharmony_ci * 41798c2ecf20Sopenharmony_ci * Note: Guest and host CPUID.(EAX=07H,ECX=0H):EBX[bit 13] (deprecate FPU CS 41808c2ecf20Sopenharmony_ci * and FPU DS) should match. 41818c2ecf20Sopenharmony_ci */ 41828c2ecf20Sopenharmony_cistatic int em_fxsave(struct x86_emulate_ctxt *ctxt) 41838c2ecf20Sopenharmony_ci{ 41848c2ecf20Sopenharmony_ci struct fxregs_state fx_state; 41858c2ecf20Sopenharmony_ci int rc; 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci rc = check_fxsr(ctxt); 41888c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 41898c2ecf20Sopenharmony_ci return rc; 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_ci emulator_get_fpu(); 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state)); 41948c2ecf20Sopenharmony_ci 41958c2ecf20Sopenharmony_ci emulator_put_fpu(); 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 41988c2ecf20Sopenharmony_ci return rc; 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci return segmented_write_std(ctxt, ctxt->memop.addr.mem, &fx_state, 42018c2ecf20Sopenharmony_ci fxstate_size(ctxt)); 42028c2ecf20Sopenharmony_ci} 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci/* 42058c2ecf20Sopenharmony_ci * FXRSTOR might restore XMM registers not provided by the guest. Fill 42068c2ecf20Sopenharmony_ci * in the host registers (via FXSAVE) instead, so they won't be modified. 42078c2ecf20Sopenharmony_ci * (preemption has to stay disabled until FXRSTOR). 42088c2ecf20Sopenharmony_ci * 42098c2ecf20Sopenharmony_ci * Use noinline to keep the stack for other functions called by callers small. 42108c2ecf20Sopenharmony_ci */ 42118c2ecf20Sopenharmony_cistatic noinline int fxregs_fixup(struct fxregs_state *fx_state, 42128c2ecf20Sopenharmony_ci const size_t used_size) 42138c2ecf20Sopenharmony_ci{ 42148c2ecf20Sopenharmony_ci struct fxregs_state fx_tmp; 42158c2ecf20Sopenharmony_ci int rc; 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_tmp)); 42188c2ecf20Sopenharmony_ci memcpy((void *)fx_state + used_size, (void *)&fx_tmp + used_size, 42198c2ecf20Sopenharmony_ci __fxstate_size(16) - used_size); 42208c2ecf20Sopenharmony_ci 42218c2ecf20Sopenharmony_ci return rc; 42228c2ecf20Sopenharmony_ci} 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_cistatic int em_fxrstor(struct x86_emulate_ctxt *ctxt) 42258c2ecf20Sopenharmony_ci{ 42268c2ecf20Sopenharmony_ci struct fxregs_state fx_state; 42278c2ecf20Sopenharmony_ci int rc; 42288c2ecf20Sopenharmony_ci size_t size; 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci rc = check_fxsr(ctxt); 42318c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 42328c2ecf20Sopenharmony_ci return rc; 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci size = fxstate_size(ctxt); 42358c2ecf20Sopenharmony_ci rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, size); 42368c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 42378c2ecf20Sopenharmony_ci return rc; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci emulator_get_fpu(); 42408c2ecf20Sopenharmony_ci 42418c2ecf20Sopenharmony_ci if (size < __fxstate_size(16)) { 42428c2ecf20Sopenharmony_ci rc = fxregs_fixup(&fx_state, size); 42438c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 42448c2ecf20Sopenharmony_ci goto out; 42458c2ecf20Sopenharmony_ci } 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci if (fx_state.mxcsr >> 16) { 42488c2ecf20Sopenharmony_ci rc = emulate_gp(ctxt, 0); 42498c2ecf20Sopenharmony_ci goto out; 42508c2ecf20Sopenharmony_ci } 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) 42538c2ecf20Sopenharmony_ci rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state)); 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ciout: 42568c2ecf20Sopenharmony_ci emulator_put_fpu(); 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci return rc; 42598c2ecf20Sopenharmony_ci} 42608c2ecf20Sopenharmony_ci 42618c2ecf20Sopenharmony_cistatic int em_xsetbv(struct x86_emulate_ctxt *ctxt) 42628c2ecf20Sopenharmony_ci{ 42638c2ecf20Sopenharmony_ci u32 eax, ecx, edx; 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci eax = reg_read(ctxt, VCPU_REGS_RAX); 42668c2ecf20Sopenharmony_ci edx = reg_read(ctxt, VCPU_REGS_RDX); 42678c2ecf20Sopenharmony_ci ecx = reg_read(ctxt, VCPU_REGS_RCX); 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci if (ctxt->ops->set_xcr(ctxt, ecx, ((u64)edx << 32) | eax)) 42708c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 42738c2ecf20Sopenharmony_ci} 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_cistatic bool valid_cr(int nr) 42768c2ecf20Sopenharmony_ci{ 42778c2ecf20Sopenharmony_ci switch (nr) { 42788c2ecf20Sopenharmony_ci case 0: 42798c2ecf20Sopenharmony_ci case 2 ... 4: 42808c2ecf20Sopenharmony_ci case 8: 42818c2ecf20Sopenharmony_ci return true; 42828c2ecf20Sopenharmony_ci default: 42838c2ecf20Sopenharmony_ci return false; 42848c2ecf20Sopenharmony_ci } 42858c2ecf20Sopenharmony_ci} 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_cistatic int check_cr_access(struct x86_emulate_ctxt *ctxt) 42888c2ecf20Sopenharmony_ci{ 42898c2ecf20Sopenharmony_ci if (!valid_cr(ctxt->modrm_reg)) 42908c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 42918c2ecf20Sopenharmony_ci 42928c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 42938c2ecf20Sopenharmony_ci} 42948c2ecf20Sopenharmony_ci 42958c2ecf20Sopenharmony_cistatic int check_dr7_gd(struct x86_emulate_ctxt *ctxt) 42968c2ecf20Sopenharmony_ci{ 42978c2ecf20Sopenharmony_ci unsigned long dr7; 42988c2ecf20Sopenharmony_ci 42998c2ecf20Sopenharmony_ci ctxt->ops->get_dr(ctxt, 7, &dr7); 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ci /* Check if DR7.Global_Enable is set */ 43028c2ecf20Sopenharmony_ci return dr7 & (1 << 13); 43038c2ecf20Sopenharmony_ci} 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_cistatic int check_dr_read(struct x86_emulate_ctxt *ctxt) 43068c2ecf20Sopenharmony_ci{ 43078c2ecf20Sopenharmony_ci int dr = ctxt->modrm_reg; 43088c2ecf20Sopenharmony_ci u64 cr4; 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci if (dr > 7) 43118c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci cr4 = ctxt->ops->get_cr(ctxt, 4); 43148c2ecf20Sopenharmony_ci if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5)) 43158c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci if (check_dr7_gd(ctxt)) { 43188c2ecf20Sopenharmony_ci ulong dr6; 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci ctxt->ops->get_dr(ctxt, 6, &dr6); 43218c2ecf20Sopenharmony_ci dr6 &= ~DR_TRAP_BITS; 43228c2ecf20Sopenharmony_ci dr6 |= DR6_BD | DR6_RTM; 43238c2ecf20Sopenharmony_ci ctxt->ops->set_dr(ctxt, 6, dr6); 43248c2ecf20Sopenharmony_ci return emulate_db(ctxt); 43258c2ecf20Sopenharmony_ci } 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 43288c2ecf20Sopenharmony_ci} 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_cistatic int check_dr_write(struct x86_emulate_ctxt *ctxt) 43318c2ecf20Sopenharmony_ci{ 43328c2ecf20Sopenharmony_ci u64 new_val = ctxt->src.val64; 43338c2ecf20Sopenharmony_ci int dr = ctxt->modrm_reg; 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL)) 43368c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci return check_dr_read(ctxt); 43398c2ecf20Sopenharmony_ci} 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_cistatic int check_svme(struct x86_emulate_ctxt *ctxt) 43428c2ecf20Sopenharmony_ci{ 43438c2ecf20Sopenharmony_ci u64 efer = 0; 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci if (!(efer & EFER_SVME)) 43488c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 43518c2ecf20Sopenharmony_ci} 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_cistatic int check_svme_pa(struct x86_emulate_ctxt *ctxt) 43548c2ecf20Sopenharmony_ci{ 43558c2ecf20Sopenharmony_ci u64 rax = reg_read(ctxt, VCPU_REGS_RAX); 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci /* Valid physical address? */ 43588c2ecf20Sopenharmony_ci if (rax & 0xffff000000000000ULL) 43598c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 43608c2ecf20Sopenharmony_ci 43618c2ecf20Sopenharmony_ci return check_svme(ctxt); 43628c2ecf20Sopenharmony_ci} 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_cistatic int check_rdtsc(struct x86_emulate_ctxt *ctxt) 43658c2ecf20Sopenharmony_ci{ 43668c2ecf20Sopenharmony_ci u64 cr4 = ctxt->ops->get_cr(ctxt, 4); 43678c2ecf20Sopenharmony_ci 43688c2ecf20Sopenharmony_ci if (cr4 & X86_CR4_TSD && ctxt->ops->cpl(ctxt)) 43698c2ecf20Sopenharmony_ci return emulate_ud(ctxt); 43708c2ecf20Sopenharmony_ci 43718c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 43728c2ecf20Sopenharmony_ci} 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_cistatic int check_rdpmc(struct x86_emulate_ctxt *ctxt) 43758c2ecf20Sopenharmony_ci{ 43768c2ecf20Sopenharmony_ci u64 cr4 = ctxt->ops->get_cr(ctxt, 4); 43778c2ecf20Sopenharmony_ci u64 rcx = reg_read(ctxt, VCPU_REGS_RCX); 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci /* 43808c2ecf20Sopenharmony_ci * VMware allows access to these Pseduo-PMCs even when read via RDPMC 43818c2ecf20Sopenharmony_ci * in Ring3 when CR4.PCE=0. 43828c2ecf20Sopenharmony_ci */ 43838c2ecf20Sopenharmony_ci if (enable_vmware_backdoor && is_vmware_backdoor_pmc(rcx)) 43848c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) || 43878c2ecf20Sopenharmony_ci ctxt->ops->check_pmc(ctxt, rcx)) 43888c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 43918c2ecf20Sopenharmony_ci} 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_cistatic int check_perm_in(struct x86_emulate_ctxt *ctxt) 43948c2ecf20Sopenharmony_ci{ 43958c2ecf20Sopenharmony_ci ctxt->dst.bytes = min(ctxt->dst.bytes, 4u); 43968c2ecf20Sopenharmony_ci if (!emulator_io_permited(ctxt, ctxt->src.val, ctxt->dst.bytes)) 43978c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 44008c2ecf20Sopenharmony_ci} 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_cistatic int check_perm_out(struct x86_emulate_ctxt *ctxt) 44038c2ecf20Sopenharmony_ci{ 44048c2ecf20Sopenharmony_ci ctxt->src.bytes = min(ctxt->src.bytes, 4u); 44058c2ecf20Sopenharmony_ci if (!emulator_io_permited(ctxt, ctxt->dst.val, ctxt->src.bytes)) 44068c2ecf20Sopenharmony_ci return emulate_gp(ctxt, 0); 44078c2ecf20Sopenharmony_ci 44088c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 44098c2ecf20Sopenharmony_ci} 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci#define D(_y) { .flags = (_y) } 44128c2ecf20Sopenharmony_ci#define DI(_y, _i) { .flags = (_y)|Intercept, .intercept = x86_intercept_##_i } 44138c2ecf20Sopenharmony_ci#define DIP(_y, _i, _p) { .flags = (_y)|Intercept|CheckPerm, \ 44148c2ecf20Sopenharmony_ci .intercept = x86_intercept_##_i, .check_perm = (_p) } 44158c2ecf20Sopenharmony_ci#define N D(NotImpl) 44168c2ecf20Sopenharmony_ci#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) } 44178c2ecf20Sopenharmony_ci#define G(_f, _g) { .flags = ((_f) | Group | ModRM), .u.group = (_g) } 44188c2ecf20Sopenharmony_ci#define GD(_f, _g) { .flags = ((_f) | GroupDual | ModRM), .u.gdual = (_g) } 44198c2ecf20Sopenharmony_ci#define ID(_f, _i) { .flags = ((_f) | InstrDual | ModRM), .u.idual = (_i) } 44208c2ecf20Sopenharmony_ci#define MD(_f, _m) { .flags = ((_f) | ModeDual), .u.mdual = (_m) } 44218c2ecf20Sopenharmony_ci#define E(_f, _e) { .flags = ((_f) | Escape | ModRM), .u.esc = (_e) } 44228c2ecf20Sopenharmony_ci#define I(_f, _e) { .flags = (_f), .u.execute = (_e) } 44238c2ecf20Sopenharmony_ci#define F(_f, _e) { .flags = (_f) | Fastop, .u.fastop = (_e) } 44248c2ecf20Sopenharmony_ci#define II(_f, _e, _i) \ 44258c2ecf20Sopenharmony_ci { .flags = (_f)|Intercept, .u.execute = (_e), .intercept = x86_intercept_##_i } 44268c2ecf20Sopenharmony_ci#define IIP(_f, _e, _i, _p) \ 44278c2ecf20Sopenharmony_ci { .flags = (_f)|Intercept|CheckPerm, .u.execute = (_e), \ 44288c2ecf20Sopenharmony_ci .intercept = x86_intercept_##_i, .check_perm = (_p) } 44298c2ecf20Sopenharmony_ci#define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) } 44308c2ecf20Sopenharmony_ci 44318c2ecf20Sopenharmony_ci#define D2bv(_f) D((_f) | ByteOp), D(_f) 44328c2ecf20Sopenharmony_ci#define D2bvIP(_f, _i, _p) DIP((_f) | ByteOp, _i, _p), DIP(_f, _i, _p) 44338c2ecf20Sopenharmony_ci#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e) 44348c2ecf20Sopenharmony_ci#define F2bv(_f, _e) F((_f) | ByteOp, _e), F(_f, _e) 44358c2ecf20Sopenharmony_ci#define I2bvIP(_f, _e, _i, _p) \ 44368c2ecf20Sopenharmony_ci IIP((_f) | ByteOp, _e, _i, _p), IIP(_f, _e, _i, _p) 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci#define F6ALU(_f, _e) F2bv((_f) | DstMem | SrcReg | ModRM, _e), \ 44398c2ecf20Sopenharmony_ci F2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \ 44408c2ecf20Sopenharmony_ci F2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e) 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_cistatic const struct opcode group7_rm0[] = { 44438c2ecf20Sopenharmony_ci N, 44448c2ecf20Sopenharmony_ci I(SrcNone | Priv | EmulateOnUD, em_hypercall), 44458c2ecf20Sopenharmony_ci N, N, N, N, N, N, 44468c2ecf20Sopenharmony_ci}; 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_cistatic const struct opcode group7_rm1[] = { 44498c2ecf20Sopenharmony_ci DI(SrcNone | Priv, monitor), 44508c2ecf20Sopenharmony_ci DI(SrcNone | Priv, mwait), 44518c2ecf20Sopenharmony_ci N, N, N, N, N, N, 44528c2ecf20Sopenharmony_ci}; 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_cistatic const struct opcode group7_rm2[] = { 44558c2ecf20Sopenharmony_ci N, 44568c2ecf20Sopenharmony_ci II(ImplicitOps | Priv, em_xsetbv, xsetbv), 44578c2ecf20Sopenharmony_ci N, N, N, N, N, N, 44588c2ecf20Sopenharmony_ci}; 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_cistatic const struct opcode group7_rm3[] = { 44618c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, vmrun, check_svme_pa), 44628c2ecf20Sopenharmony_ci II(SrcNone | Prot | EmulateOnUD, em_hypercall, vmmcall), 44638c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, vmload, check_svme_pa), 44648c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, vmsave, check_svme_pa), 44658c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, stgi, check_svme), 44668c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, clgi, check_svme), 44678c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, skinit, check_svme), 44688c2ecf20Sopenharmony_ci DIP(SrcNone | Prot | Priv, invlpga, check_svme), 44698c2ecf20Sopenharmony_ci}; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_cistatic const struct opcode group7_rm7[] = { 44728c2ecf20Sopenharmony_ci N, 44738c2ecf20Sopenharmony_ci DIP(SrcNone, rdtscp, check_rdtsc), 44748c2ecf20Sopenharmony_ci N, N, N, N, N, N, 44758c2ecf20Sopenharmony_ci}; 44768c2ecf20Sopenharmony_ci 44778c2ecf20Sopenharmony_cistatic const struct opcode group1[] = { 44788c2ecf20Sopenharmony_ci F(Lock, em_add), 44798c2ecf20Sopenharmony_ci F(Lock | PageTable, em_or), 44808c2ecf20Sopenharmony_ci F(Lock, em_adc), 44818c2ecf20Sopenharmony_ci F(Lock, em_sbb), 44828c2ecf20Sopenharmony_ci F(Lock | PageTable, em_and), 44838c2ecf20Sopenharmony_ci F(Lock, em_sub), 44848c2ecf20Sopenharmony_ci F(Lock, em_xor), 44858c2ecf20Sopenharmony_ci F(NoWrite, em_cmp), 44868c2ecf20Sopenharmony_ci}; 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_cistatic const struct opcode group1A[] = { 44898c2ecf20Sopenharmony_ci I(DstMem | SrcNone | Mov | Stack | IncSP | TwoMemOp, em_pop), N, N, N, N, N, N, N, 44908c2ecf20Sopenharmony_ci}; 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_cistatic const struct opcode group2[] = { 44938c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_rol), 44948c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_ror), 44958c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_rcl), 44968c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_rcr), 44978c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_shl), 44988c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_shr), 44998c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_shl), 45008c2ecf20Sopenharmony_ci F(DstMem | ModRM, em_sar), 45018c2ecf20Sopenharmony_ci}; 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_cistatic const struct opcode group3[] = { 45048c2ecf20Sopenharmony_ci F(DstMem | SrcImm | NoWrite, em_test), 45058c2ecf20Sopenharmony_ci F(DstMem | SrcImm | NoWrite, em_test), 45068c2ecf20Sopenharmony_ci F(DstMem | SrcNone | Lock, em_not), 45078c2ecf20Sopenharmony_ci F(DstMem | SrcNone | Lock, em_neg), 45088c2ecf20Sopenharmony_ci F(DstXacc | Src2Mem, em_mul_ex), 45098c2ecf20Sopenharmony_ci F(DstXacc | Src2Mem, em_imul_ex), 45108c2ecf20Sopenharmony_ci F(DstXacc | Src2Mem, em_div_ex), 45118c2ecf20Sopenharmony_ci F(DstXacc | Src2Mem, em_idiv_ex), 45128c2ecf20Sopenharmony_ci}; 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_cistatic const struct opcode group4[] = { 45158c2ecf20Sopenharmony_ci F(ByteOp | DstMem | SrcNone | Lock, em_inc), 45168c2ecf20Sopenharmony_ci F(ByteOp | DstMem | SrcNone | Lock, em_dec), 45178c2ecf20Sopenharmony_ci N, N, N, N, N, N, 45188c2ecf20Sopenharmony_ci}; 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_cistatic const struct opcode group5[] = { 45218c2ecf20Sopenharmony_ci F(DstMem | SrcNone | Lock, em_inc), 45228c2ecf20Sopenharmony_ci F(DstMem | SrcNone | Lock, em_dec), 45238c2ecf20Sopenharmony_ci I(SrcMem | NearBranch, em_call_near_abs), 45248c2ecf20Sopenharmony_ci I(SrcMemFAddr | ImplicitOps, em_call_far), 45258c2ecf20Sopenharmony_ci I(SrcMem | NearBranch, em_jmp_abs), 45268c2ecf20Sopenharmony_ci I(SrcMemFAddr | ImplicitOps, em_jmp_far), 45278c2ecf20Sopenharmony_ci I(SrcMem | Stack | TwoMemOp, em_push), D(Undefined), 45288c2ecf20Sopenharmony_ci}; 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_cistatic const struct opcode group6[] = { 45318c2ecf20Sopenharmony_ci II(Prot | DstMem, em_sldt, sldt), 45328c2ecf20Sopenharmony_ci II(Prot | DstMem, em_str, str), 45338c2ecf20Sopenharmony_ci II(Prot | Priv | SrcMem16, em_lldt, lldt), 45348c2ecf20Sopenharmony_ci II(Prot | Priv | SrcMem16, em_ltr, ltr), 45358c2ecf20Sopenharmony_ci N, N, N, N, 45368c2ecf20Sopenharmony_ci}; 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_cistatic const struct group_dual group7 = { { 45398c2ecf20Sopenharmony_ci II(Mov | DstMem, em_sgdt, sgdt), 45408c2ecf20Sopenharmony_ci II(Mov | DstMem, em_sidt, sidt), 45418c2ecf20Sopenharmony_ci II(SrcMem | Priv, em_lgdt, lgdt), 45428c2ecf20Sopenharmony_ci II(SrcMem | Priv, em_lidt, lidt), 45438c2ecf20Sopenharmony_ci II(SrcNone | DstMem | Mov, em_smsw, smsw), N, 45448c2ecf20Sopenharmony_ci II(SrcMem16 | Mov | Priv, em_lmsw, lmsw), 45458c2ecf20Sopenharmony_ci II(SrcMem | ByteOp | Priv | NoAccess, em_invlpg, invlpg), 45468c2ecf20Sopenharmony_ci}, { 45478c2ecf20Sopenharmony_ci EXT(0, group7_rm0), 45488c2ecf20Sopenharmony_ci EXT(0, group7_rm1), 45498c2ecf20Sopenharmony_ci EXT(0, group7_rm2), 45508c2ecf20Sopenharmony_ci EXT(0, group7_rm3), 45518c2ecf20Sopenharmony_ci II(SrcNone | DstMem | Mov, em_smsw, smsw), N, 45528c2ecf20Sopenharmony_ci II(SrcMem16 | Mov | Priv, em_lmsw, lmsw), 45538c2ecf20Sopenharmony_ci EXT(0, group7_rm7), 45548c2ecf20Sopenharmony_ci} }; 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_cistatic const struct opcode group8[] = { 45578c2ecf20Sopenharmony_ci N, N, N, N, 45588c2ecf20Sopenharmony_ci F(DstMem | SrcImmByte | NoWrite, em_bt), 45598c2ecf20Sopenharmony_ci F(DstMem | SrcImmByte | Lock | PageTable, em_bts), 45608c2ecf20Sopenharmony_ci F(DstMem | SrcImmByte | Lock, em_btr), 45618c2ecf20Sopenharmony_ci F(DstMem | SrcImmByte | Lock | PageTable, em_btc), 45628c2ecf20Sopenharmony_ci}; 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci/* 45658c2ecf20Sopenharmony_ci * The "memory" destination is actually always a register, since we come 45668c2ecf20Sopenharmony_ci * from the register case of group9. 45678c2ecf20Sopenharmony_ci */ 45688c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_c7_7 = { 45698c2ecf20Sopenharmony_ci N, N, N, II(DstMem | ModRM | Op3264 | EmulateOnUD, em_rdpid, rdpid), 45708c2ecf20Sopenharmony_ci}; 45718c2ecf20Sopenharmony_ci 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_cistatic const struct group_dual group9 = { { 45748c2ecf20Sopenharmony_ci N, I(DstMem64 | Lock | PageTable, em_cmpxchg8b), N, N, N, N, N, N, 45758c2ecf20Sopenharmony_ci}, { 45768c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, 45778c2ecf20Sopenharmony_ci GP(0, &pfx_0f_c7_7), 45788c2ecf20Sopenharmony_ci} }; 45798c2ecf20Sopenharmony_ci 45808c2ecf20Sopenharmony_cistatic const struct opcode group11[] = { 45818c2ecf20Sopenharmony_ci I(DstMem | SrcImm | Mov | PageTable, em_mov), 45828c2ecf20Sopenharmony_ci X7(D(Undefined)), 45838c2ecf20Sopenharmony_ci}; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_ae_7 = { 45868c2ecf20Sopenharmony_ci I(SrcMem | ByteOp, em_clflush), I(SrcMem | ByteOp, em_clflushopt), N, N, 45878c2ecf20Sopenharmony_ci}; 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_cistatic const struct group_dual group15 = { { 45908c2ecf20Sopenharmony_ci I(ModRM | Aligned16, em_fxsave), 45918c2ecf20Sopenharmony_ci I(ModRM | Aligned16, em_fxrstor), 45928c2ecf20Sopenharmony_ci N, N, N, N, N, GP(0, &pfx_0f_ae_7), 45938c2ecf20Sopenharmony_ci}, { 45948c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 45958c2ecf20Sopenharmony_ci} }; 45968c2ecf20Sopenharmony_ci 45978c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_6f_0f_7f = { 45988c2ecf20Sopenharmony_ci I(Mmx, em_mov), I(Sse | Aligned, em_mov), N, I(Sse | Unaligned, em_mov), 45998c2ecf20Sopenharmony_ci}; 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_cistatic const struct instr_dual instr_dual_0f_2b = { 46028c2ecf20Sopenharmony_ci I(0, em_mov), N 46038c2ecf20Sopenharmony_ci}; 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_2b = { 46068c2ecf20Sopenharmony_ci ID(0, &instr_dual_0f_2b), ID(0, &instr_dual_0f_2b), N, N, 46078c2ecf20Sopenharmony_ci}; 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_10_0f_11 = { 46108c2ecf20Sopenharmony_ci I(Unaligned, em_mov), I(Unaligned, em_mov), N, N, 46118c2ecf20Sopenharmony_ci}; 46128c2ecf20Sopenharmony_ci 46138c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_28_0f_29 = { 46148c2ecf20Sopenharmony_ci I(Aligned, em_mov), I(Aligned, em_mov), N, N, 46158c2ecf20Sopenharmony_ci}; 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_cistatic const struct gprefix pfx_0f_e7 = { 46188c2ecf20Sopenharmony_ci N, I(Sse, em_mov), N, N, 46198c2ecf20Sopenharmony_ci}; 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_cistatic const struct escape escape_d9 = { { 46228c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, I(DstMem16 | Mov, em_fnstcw), 46238c2ecf20Sopenharmony_ci}, { 46248c2ecf20Sopenharmony_ci /* 0xC0 - 0xC7 */ 46258c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46268c2ecf20Sopenharmony_ci /* 0xC8 - 0xCF */ 46278c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46288c2ecf20Sopenharmony_ci /* 0xD0 - 0xC7 */ 46298c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46308c2ecf20Sopenharmony_ci /* 0xD8 - 0xDF */ 46318c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46328c2ecf20Sopenharmony_ci /* 0xE0 - 0xE7 */ 46338c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46348c2ecf20Sopenharmony_ci /* 0xE8 - 0xEF */ 46358c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46368c2ecf20Sopenharmony_ci /* 0xF0 - 0xF7 */ 46378c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46388c2ecf20Sopenharmony_ci /* 0xF8 - 0xFF */ 46398c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46408c2ecf20Sopenharmony_ci} }; 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_cistatic const struct escape escape_db = { { 46438c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46448c2ecf20Sopenharmony_ci}, { 46458c2ecf20Sopenharmony_ci /* 0xC0 - 0xC7 */ 46468c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46478c2ecf20Sopenharmony_ci /* 0xC8 - 0xCF */ 46488c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46498c2ecf20Sopenharmony_ci /* 0xD0 - 0xC7 */ 46508c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46518c2ecf20Sopenharmony_ci /* 0xD8 - 0xDF */ 46528c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46538c2ecf20Sopenharmony_ci /* 0xE0 - 0xE7 */ 46548c2ecf20Sopenharmony_ci N, N, N, I(ImplicitOps, em_fninit), N, N, N, N, 46558c2ecf20Sopenharmony_ci /* 0xE8 - 0xEF */ 46568c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46578c2ecf20Sopenharmony_ci /* 0xF0 - 0xF7 */ 46588c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46598c2ecf20Sopenharmony_ci /* 0xF8 - 0xFF */ 46608c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46618c2ecf20Sopenharmony_ci} }; 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_cistatic const struct escape escape_dd = { { 46648c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, I(DstMem16 | Mov, em_fnstsw), 46658c2ecf20Sopenharmony_ci}, { 46668c2ecf20Sopenharmony_ci /* 0xC0 - 0xC7 */ 46678c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46688c2ecf20Sopenharmony_ci /* 0xC8 - 0xCF */ 46698c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46708c2ecf20Sopenharmony_ci /* 0xD0 - 0xC7 */ 46718c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46728c2ecf20Sopenharmony_ci /* 0xD8 - 0xDF */ 46738c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46748c2ecf20Sopenharmony_ci /* 0xE0 - 0xE7 */ 46758c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46768c2ecf20Sopenharmony_ci /* 0xE8 - 0xEF */ 46778c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46788c2ecf20Sopenharmony_ci /* 0xF0 - 0xF7 */ 46798c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46808c2ecf20Sopenharmony_ci /* 0xF8 - 0xFF */ 46818c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 46828c2ecf20Sopenharmony_ci} }; 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_cistatic const struct instr_dual instr_dual_0f_c3 = { 46858c2ecf20Sopenharmony_ci I(DstMem | SrcReg | ModRM | No16 | Mov, em_mov), N 46868c2ecf20Sopenharmony_ci}; 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_cistatic const struct mode_dual mode_dual_63 = { 46898c2ecf20Sopenharmony_ci N, I(DstReg | SrcMem32 | ModRM | Mov, em_movsxd) 46908c2ecf20Sopenharmony_ci}; 46918c2ecf20Sopenharmony_ci 46928c2ecf20Sopenharmony_cistatic const struct opcode opcode_table[256] = { 46938c2ecf20Sopenharmony_ci /* 0x00 - 0x07 */ 46948c2ecf20Sopenharmony_ci F6ALU(Lock, em_add), 46958c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2ES, em_push_sreg), 46968c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2ES, em_pop_sreg), 46978c2ecf20Sopenharmony_ci /* 0x08 - 0x0F */ 46988c2ecf20Sopenharmony_ci F6ALU(Lock | PageTable, em_or), 46998c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2CS, em_push_sreg), 47008c2ecf20Sopenharmony_ci N, 47018c2ecf20Sopenharmony_ci /* 0x10 - 0x17 */ 47028c2ecf20Sopenharmony_ci F6ALU(Lock, em_adc), 47038c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2SS, em_push_sreg), 47048c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2SS, em_pop_sreg), 47058c2ecf20Sopenharmony_ci /* 0x18 - 0x1F */ 47068c2ecf20Sopenharmony_ci F6ALU(Lock, em_sbb), 47078c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2DS, em_push_sreg), 47088c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64 | Src2DS, em_pop_sreg), 47098c2ecf20Sopenharmony_ci /* 0x20 - 0x27 */ 47108c2ecf20Sopenharmony_ci F6ALU(Lock | PageTable, em_and), N, N, 47118c2ecf20Sopenharmony_ci /* 0x28 - 0x2F */ 47128c2ecf20Sopenharmony_ci F6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das), 47138c2ecf20Sopenharmony_ci /* 0x30 - 0x37 */ 47148c2ecf20Sopenharmony_ci F6ALU(Lock, em_xor), N, N, 47158c2ecf20Sopenharmony_ci /* 0x38 - 0x3F */ 47168c2ecf20Sopenharmony_ci F6ALU(NoWrite, em_cmp), N, N, 47178c2ecf20Sopenharmony_ci /* 0x40 - 0x4F */ 47188c2ecf20Sopenharmony_ci X8(F(DstReg, em_inc)), X8(F(DstReg, em_dec)), 47198c2ecf20Sopenharmony_ci /* 0x50 - 0x57 */ 47208c2ecf20Sopenharmony_ci X8(I(SrcReg | Stack, em_push)), 47218c2ecf20Sopenharmony_ci /* 0x58 - 0x5F */ 47228c2ecf20Sopenharmony_ci X8(I(DstReg | Stack, em_pop)), 47238c2ecf20Sopenharmony_ci /* 0x60 - 0x67 */ 47248c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64, em_pusha), 47258c2ecf20Sopenharmony_ci I(ImplicitOps | Stack | No64, em_popa), 47268c2ecf20Sopenharmony_ci N, MD(ModRM, &mode_dual_63), 47278c2ecf20Sopenharmony_ci N, N, N, N, 47288c2ecf20Sopenharmony_ci /* 0x68 - 0x6F */ 47298c2ecf20Sopenharmony_ci I(SrcImm | Mov | Stack, em_push), 47308c2ecf20Sopenharmony_ci I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op), 47318c2ecf20Sopenharmony_ci I(SrcImmByte | Mov | Stack, em_push), 47328c2ecf20Sopenharmony_ci I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op), 47338c2ecf20Sopenharmony_ci I2bvIP(DstDI | SrcDX | Mov | String | Unaligned, em_in, ins, check_perm_in), /* insb, insw/insd */ 47348c2ecf20Sopenharmony_ci I2bvIP(SrcSI | DstDX | String, em_out, outs, check_perm_out), /* outsb, outsw/outsd */ 47358c2ecf20Sopenharmony_ci /* 0x70 - 0x7F */ 47368c2ecf20Sopenharmony_ci X16(D(SrcImmByte | NearBranch)), 47378c2ecf20Sopenharmony_ci /* 0x80 - 0x87 */ 47388c2ecf20Sopenharmony_ci G(ByteOp | DstMem | SrcImm, group1), 47398c2ecf20Sopenharmony_ci G(DstMem | SrcImm, group1), 47408c2ecf20Sopenharmony_ci G(ByteOp | DstMem | SrcImm | No64, group1), 47418c2ecf20Sopenharmony_ci G(DstMem | SrcImmByte, group1), 47428c2ecf20Sopenharmony_ci F2bv(DstMem | SrcReg | ModRM | NoWrite, em_test), 47438c2ecf20Sopenharmony_ci I2bv(DstMem | SrcReg | ModRM | Lock | PageTable, em_xchg), 47448c2ecf20Sopenharmony_ci /* 0x88 - 0x8F */ 47458c2ecf20Sopenharmony_ci I2bv(DstMem | SrcReg | ModRM | Mov | PageTable, em_mov), 47468c2ecf20Sopenharmony_ci I2bv(DstReg | SrcMem | ModRM | Mov, em_mov), 47478c2ecf20Sopenharmony_ci I(DstMem | SrcNone | ModRM | Mov | PageTable, em_mov_rm_sreg), 47488c2ecf20Sopenharmony_ci D(ModRM | SrcMem | NoAccess | DstReg), 47498c2ecf20Sopenharmony_ci I(ImplicitOps | SrcMem16 | ModRM, em_mov_sreg_rm), 47508c2ecf20Sopenharmony_ci G(0, group1A), 47518c2ecf20Sopenharmony_ci /* 0x90 - 0x97 */ 47528c2ecf20Sopenharmony_ci DI(SrcAcc | DstReg, pause), X7(D(SrcAcc | DstReg)), 47538c2ecf20Sopenharmony_ci /* 0x98 - 0x9F */ 47548c2ecf20Sopenharmony_ci D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd), 47558c2ecf20Sopenharmony_ci I(SrcImmFAddr | No64, em_call_far), N, 47568c2ecf20Sopenharmony_ci II(ImplicitOps | Stack, em_pushf, pushf), 47578c2ecf20Sopenharmony_ci II(ImplicitOps | Stack, em_popf, popf), 47588c2ecf20Sopenharmony_ci I(ImplicitOps, em_sahf), I(ImplicitOps, em_lahf), 47598c2ecf20Sopenharmony_ci /* 0xA0 - 0xA7 */ 47608c2ecf20Sopenharmony_ci I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov), 47618c2ecf20Sopenharmony_ci I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov), 47628c2ecf20Sopenharmony_ci I2bv(SrcSI | DstDI | Mov | String | TwoMemOp, em_mov), 47638c2ecf20Sopenharmony_ci F2bv(SrcSI | DstDI | String | NoWrite | TwoMemOp, em_cmp_r), 47648c2ecf20Sopenharmony_ci /* 0xA8 - 0xAF */ 47658c2ecf20Sopenharmony_ci F2bv(DstAcc | SrcImm | NoWrite, em_test), 47668c2ecf20Sopenharmony_ci I2bv(SrcAcc | DstDI | Mov | String, em_mov), 47678c2ecf20Sopenharmony_ci I2bv(SrcSI | DstAcc | Mov | String, em_mov), 47688c2ecf20Sopenharmony_ci F2bv(SrcAcc | DstDI | String | NoWrite, em_cmp_r), 47698c2ecf20Sopenharmony_ci /* 0xB0 - 0xB7 */ 47708c2ecf20Sopenharmony_ci X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)), 47718c2ecf20Sopenharmony_ci /* 0xB8 - 0xBF */ 47728c2ecf20Sopenharmony_ci X8(I(DstReg | SrcImm64 | Mov, em_mov)), 47738c2ecf20Sopenharmony_ci /* 0xC0 - 0xC7 */ 47748c2ecf20Sopenharmony_ci G(ByteOp | Src2ImmByte, group2), G(Src2ImmByte, group2), 47758c2ecf20Sopenharmony_ci I(ImplicitOps | NearBranch | SrcImmU16, em_ret_near_imm), 47768c2ecf20Sopenharmony_ci I(ImplicitOps | NearBranch, em_ret), 47778c2ecf20Sopenharmony_ci I(DstReg | SrcMemFAddr | ModRM | No64 | Src2ES, em_lseg), 47788c2ecf20Sopenharmony_ci I(DstReg | SrcMemFAddr | ModRM | No64 | Src2DS, em_lseg), 47798c2ecf20Sopenharmony_ci G(ByteOp, group11), G(0, group11), 47808c2ecf20Sopenharmony_ci /* 0xC8 - 0xCF */ 47818c2ecf20Sopenharmony_ci I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave), 47828c2ecf20Sopenharmony_ci I(ImplicitOps | SrcImmU16, em_ret_far_imm), 47838c2ecf20Sopenharmony_ci I(ImplicitOps, em_ret_far), 47848c2ecf20Sopenharmony_ci D(ImplicitOps), DI(SrcImmByte, intn), 47858c2ecf20Sopenharmony_ci D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), 47868c2ecf20Sopenharmony_ci /* 0xD0 - 0xD7 */ 47878c2ecf20Sopenharmony_ci G(Src2One | ByteOp, group2), G(Src2One, group2), 47888c2ecf20Sopenharmony_ci G(Src2CL | ByteOp, group2), G(Src2CL, group2), 47898c2ecf20Sopenharmony_ci I(DstAcc | SrcImmUByte | No64, em_aam), 47908c2ecf20Sopenharmony_ci I(DstAcc | SrcImmUByte | No64, em_aad), 47918c2ecf20Sopenharmony_ci F(DstAcc | ByteOp | No64, em_salc), 47928c2ecf20Sopenharmony_ci I(DstAcc | SrcXLat | ByteOp, em_mov), 47938c2ecf20Sopenharmony_ci /* 0xD8 - 0xDF */ 47948c2ecf20Sopenharmony_ci N, E(0, &escape_d9), N, E(0, &escape_db), N, E(0, &escape_dd), N, N, 47958c2ecf20Sopenharmony_ci /* 0xE0 - 0xE7 */ 47968c2ecf20Sopenharmony_ci X3(I(SrcImmByte | NearBranch, em_loop)), 47978c2ecf20Sopenharmony_ci I(SrcImmByte | NearBranch, em_jcxz), 47988c2ecf20Sopenharmony_ci I2bvIP(SrcImmUByte | DstAcc, em_in, in, check_perm_in), 47998c2ecf20Sopenharmony_ci I2bvIP(SrcAcc | DstImmUByte, em_out, out, check_perm_out), 48008c2ecf20Sopenharmony_ci /* 0xE8 - 0xEF */ 48018c2ecf20Sopenharmony_ci I(SrcImm | NearBranch, em_call), D(SrcImm | ImplicitOps | NearBranch), 48028c2ecf20Sopenharmony_ci I(SrcImmFAddr | No64, em_jmp_far), 48038c2ecf20Sopenharmony_ci D(SrcImmByte | ImplicitOps | NearBranch), 48048c2ecf20Sopenharmony_ci I2bvIP(SrcDX | DstAcc, em_in, in, check_perm_in), 48058c2ecf20Sopenharmony_ci I2bvIP(SrcAcc | DstDX, em_out, out, check_perm_out), 48068c2ecf20Sopenharmony_ci /* 0xF0 - 0xF7 */ 48078c2ecf20Sopenharmony_ci N, DI(ImplicitOps, icebp), N, N, 48088c2ecf20Sopenharmony_ci DI(ImplicitOps | Priv, hlt), D(ImplicitOps), 48098c2ecf20Sopenharmony_ci G(ByteOp, group3), G(0, group3), 48108c2ecf20Sopenharmony_ci /* 0xF8 - 0xFF */ 48118c2ecf20Sopenharmony_ci D(ImplicitOps), D(ImplicitOps), 48128c2ecf20Sopenharmony_ci I(ImplicitOps, em_cli), I(ImplicitOps, em_sti), 48138c2ecf20Sopenharmony_ci D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5), 48148c2ecf20Sopenharmony_ci}; 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_cistatic const struct opcode twobyte_table[256] = { 48178c2ecf20Sopenharmony_ci /* 0x00 - 0x0F */ 48188c2ecf20Sopenharmony_ci G(0, group6), GD(0, &group7), N, N, 48198c2ecf20Sopenharmony_ci N, I(ImplicitOps | EmulateOnUD, em_syscall), 48208c2ecf20Sopenharmony_ci II(ImplicitOps | Priv, em_clts, clts), N, 48218c2ecf20Sopenharmony_ci DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N, 48228c2ecf20Sopenharmony_ci N, D(ImplicitOps | ModRM | SrcMem | NoAccess), N, N, 48238c2ecf20Sopenharmony_ci /* 0x10 - 0x1F */ 48248c2ecf20Sopenharmony_ci GP(ModRM | DstReg | SrcMem | Mov | Sse, &pfx_0f_10_0f_11), 48258c2ecf20Sopenharmony_ci GP(ModRM | DstMem | SrcReg | Mov | Sse, &pfx_0f_10_0f_11), 48268c2ecf20Sopenharmony_ci N, N, N, N, N, N, 48278c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), /* 4 * prefetch + 4 * reserved NOP */ 48288c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), N, N, 48298c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), /* 8 * reserved NOP */ 48308c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), /* 8 * reserved NOP */ 48318c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), /* 8 * reserved NOP */ 48328c2ecf20Sopenharmony_ci D(ImplicitOps | ModRM | SrcMem | NoAccess), /* NOP + 7 * reserved NOP */ 48338c2ecf20Sopenharmony_ci /* 0x20 - 0x2F */ 48348c2ecf20Sopenharmony_ci DIP(ModRM | DstMem | Priv | Op3264 | NoMod, cr_read, check_cr_access), 48358c2ecf20Sopenharmony_ci DIP(ModRM | DstMem | Priv | Op3264 | NoMod, dr_read, check_dr_read), 48368c2ecf20Sopenharmony_ci IIP(ModRM | SrcMem | Priv | Op3264 | NoMod, em_cr_write, cr_write, 48378c2ecf20Sopenharmony_ci check_cr_access), 48388c2ecf20Sopenharmony_ci IIP(ModRM | SrcMem | Priv | Op3264 | NoMod, em_dr_write, dr_write, 48398c2ecf20Sopenharmony_ci check_dr_write), 48408c2ecf20Sopenharmony_ci N, N, N, N, 48418c2ecf20Sopenharmony_ci GP(ModRM | DstReg | SrcMem | Mov | Sse, &pfx_0f_28_0f_29), 48428c2ecf20Sopenharmony_ci GP(ModRM | DstMem | SrcReg | Mov | Sse, &pfx_0f_28_0f_29), 48438c2ecf20Sopenharmony_ci N, GP(ModRM | DstMem | SrcReg | Mov | Sse, &pfx_0f_2b), 48448c2ecf20Sopenharmony_ci N, N, N, N, 48458c2ecf20Sopenharmony_ci /* 0x30 - 0x3F */ 48468c2ecf20Sopenharmony_ci II(ImplicitOps | Priv, em_wrmsr, wrmsr), 48478c2ecf20Sopenharmony_ci IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc), 48488c2ecf20Sopenharmony_ci II(ImplicitOps | Priv, em_rdmsr, rdmsr), 48498c2ecf20Sopenharmony_ci IIP(ImplicitOps, em_rdpmc, rdpmc, check_rdpmc), 48508c2ecf20Sopenharmony_ci I(ImplicitOps | EmulateOnUD, em_sysenter), 48518c2ecf20Sopenharmony_ci I(ImplicitOps | Priv | EmulateOnUD, em_sysexit), 48528c2ecf20Sopenharmony_ci N, N, 48538c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 48548c2ecf20Sopenharmony_ci /* 0x40 - 0x4F */ 48558c2ecf20Sopenharmony_ci X16(D(DstReg | SrcMem | ModRM)), 48568c2ecf20Sopenharmony_ci /* 0x50 - 0x5F */ 48578c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, 48588c2ecf20Sopenharmony_ci /* 0x60 - 0x6F */ 48598c2ecf20Sopenharmony_ci N, N, N, N, 48608c2ecf20Sopenharmony_ci N, N, N, N, 48618c2ecf20Sopenharmony_ci N, N, N, N, 48628c2ecf20Sopenharmony_ci N, N, N, GP(SrcMem | DstReg | ModRM | Mov, &pfx_0f_6f_0f_7f), 48638c2ecf20Sopenharmony_ci /* 0x70 - 0x7F */ 48648c2ecf20Sopenharmony_ci N, N, N, N, 48658c2ecf20Sopenharmony_ci N, N, N, N, 48668c2ecf20Sopenharmony_ci N, N, N, N, 48678c2ecf20Sopenharmony_ci N, N, N, GP(SrcReg | DstMem | ModRM | Mov, &pfx_0f_6f_0f_7f), 48688c2ecf20Sopenharmony_ci /* 0x80 - 0x8F */ 48698c2ecf20Sopenharmony_ci X16(D(SrcImm | NearBranch)), 48708c2ecf20Sopenharmony_ci /* 0x90 - 0x9F */ 48718c2ecf20Sopenharmony_ci X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)), 48728c2ecf20Sopenharmony_ci /* 0xA0 - 0xA7 */ 48738c2ecf20Sopenharmony_ci I(Stack | Src2FS, em_push_sreg), I(Stack | Src2FS, em_pop_sreg), 48748c2ecf20Sopenharmony_ci II(ImplicitOps, em_cpuid, cpuid), 48758c2ecf20Sopenharmony_ci F(DstMem | SrcReg | ModRM | BitOp | NoWrite, em_bt), 48768c2ecf20Sopenharmony_ci F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shld), 48778c2ecf20Sopenharmony_ci F(DstMem | SrcReg | Src2CL | ModRM, em_shld), N, N, 48788c2ecf20Sopenharmony_ci /* 0xA8 - 0xAF */ 48798c2ecf20Sopenharmony_ci I(Stack | Src2GS, em_push_sreg), I(Stack | Src2GS, em_pop_sreg), 48808c2ecf20Sopenharmony_ci II(EmulateOnUD | ImplicitOps, em_rsm, rsm), 48818c2ecf20Sopenharmony_ci F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_bts), 48828c2ecf20Sopenharmony_ci F(DstMem | SrcReg | Src2ImmByte | ModRM, em_shrd), 48838c2ecf20Sopenharmony_ci F(DstMem | SrcReg | Src2CL | ModRM, em_shrd), 48848c2ecf20Sopenharmony_ci GD(0, &group15), F(DstReg | SrcMem | ModRM, em_imul), 48858c2ecf20Sopenharmony_ci /* 0xB0 - 0xB7 */ 48868c2ecf20Sopenharmony_ci I2bv(DstMem | SrcReg | ModRM | Lock | PageTable | SrcWrite, em_cmpxchg), 48878c2ecf20Sopenharmony_ci I(DstReg | SrcMemFAddr | ModRM | Src2SS, em_lseg), 48888c2ecf20Sopenharmony_ci F(DstMem | SrcReg | ModRM | BitOp | Lock, em_btr), 48898c2ecf20Sopenharmony_ci I(DstReg | SrcMemFAddr | ModRM | Src2FS, em_lseg), 48908c2ecf20Sopenharmony_ci I(DstReg | SrcMemFAddr | ModRM | Src2GS, em_lseg), 48918c2ecf20Sopenharmony_ci D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), 48928c2ecf20Sopenharmony_ci /* 0xB8 - 0xBF */ 48938c2ecf20Sopenharmony_ci N, N, 48948c2ecf20Sopenharmony_ci G(BitOp, group8), 48958c2ecf20Sopenharmony_ci F(DstMem | SrcReg | ModRM | BitOp | Lock | PageTable, em_btc), 48968c2ecf20Sopenharmony_ci I(DstReg | SrcMem | ModRM, em_bsf_c), 48978c2ecf20Sopenharmony_ci I(DstReg | SrcMem | ModRM, em_bsr_c), 48988c2ecf20Sopenharmony_ci D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov), 48998c2ecf20Sopenharmony_ci /* 0xC0 - 0xC7 */ 49008c2ecf20Sopenharmony_ci F2bv(DstMem | SrcReg | ModRM | SrcWrite | Lock, em_xadd), 49018c2ecf20Sopenharmony_ci N, ID(0, &instr_dual_0f_c3), 49028c2ecf20Sopenharmony_ci N, N, N, GD(0, &group9), 49038c2ecf20Sopenharmony_ci /* 0xC8 - 0xCF */ 49048c2ecf20Sopenharmony_ci X8(I(DstReg, em_bswap)), 49058c2ecf20Sopenharmony_ci /* 0xD0 - 0xDF */ 49068c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, 49078c2ecf20Sopenharmony_ci /* 0xE0 - 0xEF */ 49088c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, GP(SrcReg | DstMem | ModRM | Mov, &pfx_0f_e7), 49098c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, 49108c2ecf20Sopenharmony_ci /* 0xF0 - 0xFF */ 49118c2ecf20Sopenharmony_ci N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N 49128c2ecf20Sopenharmony_ci}; 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_cistatic const struct instr_dual instr_dual_0f_38_f0 = { 49158c2ecf20Sopenharmony_ci I(DstReg | SrcMem | Mov, em_movbe), N 49168c2ecf20Sopenharmony_ci}; 49178c2ecf20Sopenharmony_ci 49188c2ecf20Sopenharmony_cistatic const struct instr_dual instr_dual_0f_38_f1 = { 49198c2ecf20Sopenharmony_ci I(DstMem | SrcReg | Mov, em_movbe), N 49208c2ecf20Sopenharmony_ci}; 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_cistatic const struct gprefix three_byte_0f_38_f0 = { 49238c2ecf20Sopenharmony_ci ID(0, &instr_dual_0f_38_f0), N, N, N 49248c2ecf20Sopenharmony_ci}; 49258c2ecf20Sopenharmony_ci 49268c2ecf20Sopenharmony_cistatic const struct gprefix three_byte_0f_38_f1 = { 49278c2ecf20Sopenharmony_ci ID(0, &instr_dual_0f_38_f1), N, N, N 49288c2ecf20Sopenharmony_ci}; 49298c2ecf20Sopenharmony_ci 49308c2ecf20Sopenharmony_ci/* 49318c2ecf20Sopenharmony_ci * Insns below are selected by the prefix which indexed by the third opcode 49328c2ecf20Sopenharmony_ci * byte. 49338c2ecf20Sopenharmony_ci */ 49348c2ecf20Sopenharmony_cistatic const struct opcode opcode_map_0f_38[256] = { 49358c2ecf20Sopenharmony_ci /* 0x00 - 0x7f */ 49368c2ecf20Sopenharmony_ci X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), 49378c2ecf20Sopenharmony_ci /* 0x80 - 0xef */ 49388c2ecf20Sopenharmony_ci X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), X16(N), 49398c2ecf20Sopenharmony_ci /* 0xf0 - 0xf1 */ 49408c2ecf20Sopenharmony_ci GP(EmulateOnUD | ModRM, &three_byte_0f_38_f0), 49418c2ecf20Sopenharmony_ci GP(EmulateOnUD | ModRM, &three_byte_0f_38_f1), 49428c2ecf20Sopenharmony_ci /* 0xf2 - 0xff */ 49438c2ecf20Sopenharmony_ci N, N, X4(N), X8(N) 49448c2ecf20Sopenharmony_ci}; 49458c2ecf20Sopenharmony_ci 49468c2ecf20Sopenharmony_ci#undef D 49478c2ecf20Sopenharmony_ci#undef N 49488c2ecf20Sopenharmony_ci#undef G 49498c2ecf20Sopenharmony_ci#undef GD 49508c2ecf20Sopenharmony_ci#undef I 49518c2ecf20Sopenharmony_ci#undef GP 49528c2ecf20Sopenharmony_ci#undef EXT 49538c2ecf20Sopenharmony_ci#undef MD 49548c2ecf20Sopenharmony_ci#undef ID 49558c2ecf20Sopenharmony_ci 49568c2ecf20Sopenharmony_ci#undef D2bv 49578c2ecf20Sopenharmony_ci#undef D2bvIP 49588c2ecf20Sopenharmony_ci#undef I2bv 49598c2ecf20Sopenharmony_ci#undef I2bvIP 49608c2ecf20Sopenharmony_ci#undef I6ALU 49618c2ecf20Sopenharmony_ci 49628c2ecf20Sopenharmony_cistatic unsigned imm_size(struct x86_emulate_ctxt *ctxt) 49638c2ecf20Sopenharmony_ci{ 49648c2ecf20Sopenharmony_ci unsigned size; 49658c2ecf20Sopenharmony_ci 49668c2ecf20Sopenharmony_ci size = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 49678c2ecf20Sopenharmony_ci if (size == 8) 49688c2ecf20Sopenharmony_ci size = 4; 49698c2ecf20Sopenharmony_ci return size; 49708c2ecf20Sopenharmony_ci} 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_cistatic int decode_imm(struct x86_emulate_ctxt *ctxt, struct operand *op, 49738c2ecf20Sopenharmony_ci unsigned size, bool sign_extension) 49748c2ecf20Sopenharmony_ci{ 49758c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci op->type = OP_IMM; 49788c2ecf20Sopenharmony_ci op->bytes = size; 49798c2ecf20Sopenharmony_ci op->addr.mem.ea = ctxt->_eip; 49808c2ecf20Sopenharmony_ci /* NB. Immediates are sign-extended as necessary. */ 49818c2ecf20Sopenharmony_ci switch (op->bytes) { 49828c2ecf20Sopenharmony_ci case 1: 49838c2ecf20Sopenharmony_ci op->val = insn_fetch(s8, ctxt); 49848c2ecf20Sopenharmony_ci break; 49858c2ecf20Sopenharmony_ci case 2: 49868c2ecf20Sopenharmony_ci op->val = insn_fetch(s16, ctxt); 49878c2ecf20Sopenharmony_ci break; 49888c2ecf20Sopenharmony_ci case 4: 49898c2ecf20Sopenharmony_ci op->val = insn_fetch(s32, ctxt); 49908c2ecf20Sopenharmony_ci break; 49918c2ecf20Sopenharmony_ci case 8: 49928c2ecf20Sopenharmony_ci op->val = insn_fetch(s64, ctxt); 49938c2ecf20Sopenharmony_ci break; 49948c2ecf20Sopenharmony_ci } 49958c2ecf20Sopenharmony_ci if (!sign_extension) { 49968c2ecf20Sopenharmony_ci switch (op->bytes) { 49978c2ecf20Sopenharmony_ci case 1: 49988c2ecf20Sopenharmony_ci op->val &= 0xff; 49998c2ecf20Sopenharmony_ci break; 50008c2ecf20Sopenharmony_ci case 2: 50018c2ecf20Sopenharmony_ci op->val &= 0xffff; 50028c2ecf20Sopenharmony_ci break; 50038c2ecf20Sopenharmony_ci case 4: 50048c2ecf20Sopenharmony_ci op->val &= 0xffffffff; 50058c2ecf20Sopenharmony_ci break; 50068c2ecf20Sopenharmony_ci } 50078c2ecf20Sopenharmony_ci } 50088c2ecf20Sopenharmony_cidone: 50098c2ecf20Sopenharmony_ci return rc; 50108c2ecf20Sopenharmony_ci} 50118c2ecf20Sopenharmony_ci 50128c2ecf20Sopenharmony_cistatic int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op, 50138c2ecf20Sopenharmony_ci unsigned d) 50148c2ecf20Sopenharmony_ci{ 50158c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 50168c2ecf20Sopenharmony_ci 50178c2ecf20Sopenharmony_ci switch (d) { 50188c2ecf20Sopenharmony_ci case OpReg: 50198c2ecf20Sopenharmony_ci decode_register_operand(ctxt, op); 50208c2ecf20Sopenharmony_ci break; 50218c2ecf20Sopenharmony_ci case OpImmUByte: 50228c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, 1, false); 50238c2ecf20Sopenharmony_ci break; 50248c2ecf20Sopenharmony_ci case OpMem: 50258c2ecf20Sopenharmony_ci ctxt->memop.bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 50268c2ecf20Sopenharmony_ci mem_common: 50278c2ecf20Sopenharmony_ci *op = ctxt->memop; 50288c2ecf20Sopenharmony_ci ctxt->memopp = op; 50298c2ecf20Sopenharmony_ci if (ctxt->d & BitOp) 50308c2ecf20Sopenharmony_ci fetch_bit_operand(ctxt); 50318c2ecf20Sopenharmony_ci op->orig_val = op->val; 50328c2ecf20Sopenharmony_ci break; 50338c2ecf20Sopenharmony_ci case OpMem64: 50348c2ecf20Sopenharmony_ci ctxt->memop.bytes = (ctxt->op_bytes == 8) ? 16 : 8; 50358c2ecf20Sopenharmony_ci goto mem_common; 50368c2ecf20Sopenharmony_ci case OpAcc: 50378c2ecf20Sopenharmony_ci op->type = OP_REG; 50388c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 50398c2ecf20Sopenharmony_ci op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX); 50408c2ecf20Sopenharmony_ci fetch_register_operand(op); 50418c2ecf20Sopenharmony_ci op->orig_val = op->val; 50428c2ecf20Sopenharmony_ci break; 50438c2ecf20Sopenharmony_ci case OpAccLo: 50448c2ecf20Sopenharmony_ci op->type = OP_REG; 50458c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 2 : ctxt->op_bytes; 50468c2ecf20Sopenharmony_ci op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX); 50478c2ecf20Sopenharmony_ci fetch_register_operand(op); 50488c2ecf20Sopenharmony_ci op->orig_val = op->val; 50498c2ecf20Sopenharmony_ci break; 50508c2ecf20Sopenharmony_ci case OpAccHi: 50518c2ecf20Sopenharmony_ci if (ctxt->d & ByteOp) { 50528c2ecf20Sopenharmony_ci op->type = OP_NONE; 50538c2ecf20Sopenharmony_ci break; 50548c2ecf20Sopenharmony_ci } 50558c2ecf20Sopenharmony_ci op->type = OP_REG; 50568c2ecf20Sopenharmony_ci op->bytes = ctxt->op_bytes; 50578c2ecf20Sopenharmony_ci op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX); 50588c2ecf20Sopenharmony_ci fetch_register_operand(op); 50598c2ecf20Sopenharmony_ci op->orig_val = op->val; 50608c2ecf20Sopenharmony_ci break; 50618c2ecf20Sopenharmony_ci case OpDI: 50628c2ecf20Sopenharmony_ci op->type = OP_MEM; 50638c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 50648c2ecf20Sopenharmony_ci op->addr.mem.ea = 50658c2ecf20Sopenharmony_ci register_address(ctxt, VCPU_REGS_RDI); 50668c2ecf20Sopenharmony_ci op->addr.mem.seg = VCPU_SREG_ES; 50678c2ecf20Sopenharmony_ci op->val = 0; 50688c2ecf20Sopenharmony_ci op->count = 1; 50698c2ecf20Sopenharmony_ci break; 50708c2ecf20Sopenharmony_ci case OpDX: 50718c2ecf20Sopenharmony_ci op->type = OP_REG; 50728c2ecf20Sopenharmony_ci op->bytes = 2; 50738c2ecf20Sopenharmony_ci op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX); 50748c2ecf20Sopenharmony_ci fetch_register_operand(op); 50758c2ecf20Sopenharmony_ci break; 50768c2ecf20Sopenharmony_ci case OpCL: 50778c2ecf20Sopenharmony_ci op->type = OP_IMM; 50788c2ecf20Sopenharmony_ci op->bytes = 1; 50798c2ecf20Sopenharmony_ci op->val = reg_read(ctxt, VCPU_REGS_RCX) & 0xff; 50808c2ecf20Sopenharmony_ci break; 50818c2ecf20Sopenharmony_ci case OpImmByte: 50828c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, 1, true); 50838c2ecf20Sopenharmony_ci break; 50848c2ecf20Sopenharmony_ci case OpOne: 50858c2ecf20Sopenharmony_ci op->type = OP_IMM; 50868c2ecf20Sopenharmony_ci op->bytes = 1; 50878c2ecf20Sopenharmony_ci op->val = 1; 50888c2ecf20Sopenharmony_ci break; 50898c2ecf20Sopenharmony_ci case OpImm: 50908c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, imm_size(ctxt), true); 50918c2ecf20Sopenharmony_ci break; 50928c2ecf20Sopenharmony_ci case OpImm64: 50938c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, ctxt->op_bytes, true); 50948c2ecf20Sopenharmony_ci break; 50958c2ecf20Sopenharmony_ci case OpMem8: 50968c2ecf20Sopenharmony_ci ctxt->memop.bytes = 1; 50978c2ecf20Sopenharmony_ci if (ctxt->memop.type == OP_REG) { 50988c2ecf20Sopenharmony_ci ctxt->memop.addr.reg = decode_register(ctxt, 50998c2ecf20Sopenharmony_ci ctxt->modrm_rm, true); 51008c2ecf20Sopenharmony_ci fetch_register_operand(&ctxt->memop); 51018c2ecf20Sopenharmony_ci } 51028c2ecf20Sopenharmony_ci goto mem_common; 51038c2ecf20Sopenharmony_ci case OpMem16: 51048c2ecf20Sopenharmony_ci ctxt->memop.bytes = 2; 51058c2ecf20Sopenharmony_ci goto mem_common; 51068c2ecf20Sopenharmony_ci case OpMem32: 51078c2ecf20Sopenharmony_ci ctxt->memop.bytes = 4; 51088c2ecf20Sopenharmony_ci goto mem_common; 51098c2ecf20Sopenharmony_ci case OpImmU16: 51108c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, 2, false); 51118c2ecf20Sopenharmony_ci break; 51128c2ecf20Sopenharmony_ci case OpImmU: 51138c2ecf20Sopenharmony_ci rc = decode_imm(ctxt, op, imm_size(ctxt), false); 51148c2ecf20Sopenharmony_ci break; 51158c2ecf20Sopenharmony_ci case OpSI: 51168c2ecf20Sopenharmony_ci op->type = OP_MEM; 51178c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 51188c2ecf20Sopenharmony_ci op->addr.mem.ea = 51198c2ecf20Sopenharmony_ci register_address(ctxt, VCPU_REGS_RSI); 51208c2ecf20Sopenharmony_ci op->addr.mem.seg = ctxt->seg_override; 51218c2ecf20Sopenharmony_ci op->val = 0; 51228c2ecf20Sopenharmony_ci op->count = 1; 51238c2ecf20Sopenharmony_ci break; 51248c2ecf20Sopenharmony_ci case OpXLat: 51258c2ecf20Sopenharmony_ci op->type = OP_MEM; 51268c2ecf20Sopenharmony_ci op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes; 51278c2ecf20Sopenharmony_ci op->addr.mem.ea = 51288c2ecf20Sopenharmony_ci address_mask(ctxt, 51298c2ecf20Sopenharmony_ci reg_read(ctxt, VCPU_REGS_RBX) + 51308c2ecf20Sopenharmony_ci (reg_read(ctxt, VCPU_REGS_RAX) & 0xff)); 51318c2ecf20Sopenharmony_ci op->addr.mem.seg = ctxt->seg_override; 51328c2ecf20Sopenharmony_ci op->val = 0; 51338c2ecf20Sopenharmony_ci break; 51348c2ecf20Sopenharmony_ci case OpImmFAddr: 51358c2ecf20Sopenharmony_ci op->type = OP_IMM; 51368c2ecf20Sopenharmony_ci op->addr.mem.ea = ctxt->_eip; 51378c2ecf20Sopenharmony_ci op->bytes = ctxt->op_bytes + 2; 51388c2ecf20Sopenharmony_ci insn_fetch_arr(op->valptr, op->bytes, ctxt); 51398c2ecf20Sopenharmony_ci break; 51408c2ecf20Sopenharmony_ci case OpMemFAddr: 51418c2ecf20Sopenharmony_ci ctxt->memop.bytes = ctxt->op_bytes + 2; 51428c2ecf20Sopenharmony_ci goto mem_common; 51438c2ecf20Sopenharmony_ci case OpES: 51448c2ecf20Sopenharmony_ci op->type = OP_IMM; 51458c2ecf20Sopenharmony_ci op->val = VCPU_SREG_ES; 51468c2ecf20Sopenharmony_ci break; 51478c2ecf20Sopenharmony_ci case OpCS: 51488c2ecf20Sopenharmony_ci op->type = OP_IMM; 51498c2ecf20Sopenharmony_ci op->val = VCPU_SREG_CS; 51508c2ecf20Sopenharmony_ci break; 51518c2ecf20Sopenharmony_ci case OpSS: 51528c2ecf20Sopenharmony_ci op->type = OP_IMM; 51538c2ecf20Sopenharmony_ci op->val = VCPU_SREG_SS; 51548c2ecf20Sopenharmony_ci break; 51558c2ecf20Sopenharmony_ci case OpDS: 51568c2ecf20Sopenharmony_ci op->type = OP_IMM; 51578c2ecf20Sopenharmony_ci op->val = VCPU_SREG_DS; 51588c2ecf20Sopenharmony_ci break; 51598c2ecf20Sopenharmony_ci case OpFS: 51608c2ecf20Sopenharmony_ci op->type = OP_IMM; 51618c2ecf20Sopenharmony_ci op->val = VCPU_SREG_FS; 51628c2ecf20Sopenharmony_ci break; 51638c2ecf20Sopenharmony_ci case OpGS: 51648c2ecf20Sopenharmony_ci op->type = OP_IMM; 51658c2ecf20Sopenharmony_ci op->val = VCPU_SREG_GS; 51668c2ecf20Sopenharmony_ci break; 51678c2ecf20Sopenharmony_ci case OpImplicit: 51688c2ecf20Sopenharmony_ci /* Special instructions do their own operand decoding. */ 51698c2ecf20Sopenharmony_ci default: 51708c2ecf20Sopenharmony_ci op->type = OP_NONE; /* Disable writeback. */ 51718c2ecf20Sopenharmony_ci break; 51728c2ecf20Sopenharmony_ci } 51738c2ecf20Sopenharmony_ci 51748c2ecf20Sopenharmony_cidone: 51758c2ecf20Sopenharmony_ci return rc; 51768c2ecf20Sopenharmony_ci} 51778c2ecf20Sopenharmony_ci 51788c2ecf20Sopenharmony_ciint x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) 51798c2ecf20Sopenharmony_ci{ 51808c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 51818c2ecf20Sopenharmony_ci int mode = ctxt->mode; 51828c2ecf20Sopenharmony_ci int def_op_bytes, def_ad_bytes, goffset, simd_prefix; 51838c2ecf20Sopenharmony_ci bool op_prefix = false; 51848c2ecf20Sopenharmony_ci bool has_seg_override = false; 51858c2ecf20Sopenharmony_ci struct opcode opcode; 51868c2ecf20Sopenharmony_ci u16 dummy; 51878c2ecf20Sopenharmony_ci struct desc_struct desc; 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci ctxt->memop.type = OP_NONE; 51908c2ecf20Sopenharmony_ci ctxt->memopp = NULL; 51918c2ecf20Sopenharmony_ci ctxt->_eip = ctxt->eip; 51928c2ecf20Sopenharmony_ci ctxt->fetch.ptr = ctxt->fetch.data; 51938c2ecf20Sopenharmony_ci ctxt->fetch.end = ctxt->fetch.data + insn_len; 51948c2ecf20Sopenharmony_ci ctxt->opcode_len = 1; 51958c2ecf20Sopenharmony_ci ctxt->intercept = x86_intercept_none; 51968c2ecf20Sopenharmony_ci if (insn_len > 0) 51978c2ecf20Sopenharmony_ci memcpy(ctxt->fetch.data, insn, insn_len); 51988c2ecf20Sopenharmony_ci else { 51998c2ecf20Sopenharmony_ci rc = __do_insn_fetch_bytes(ctxt, 1); 52008c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 52018c2ecf20Sopenharmony_ci goto done; 52028c2ecf20Sopenharmony_ci } 52038c2ecf20Sopenharmony_ci 52048c2ecf20Sopenharmony_ci switch (mode) { 52058c2ecf20Sopenharmony_ci case X86EMUL_MODE_REAL: 52068c2ecf20Sopenharmony_ci case X86EMUL_MODE_VM86: 52078c2ecf20Sopenharmony_ci def_op_bytes = def_ad_bytes = 2; 52088c2ecf20Sopenharmony_ci ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS); 52098c2ecf20Sopenharmony_ci if (desc.d) 52108c2ecf20Sopenharmony_ci def_op_bytes = def_ad_bytes = 4; 52118c2ecf20Sopenharmony_ci break; 52128c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT16: 52138c2ecf20Sopenharmony_ci def_op_bytes = def_ad_bytes = 2; 52148c2ecf20Sopenharmony_ci break; 52158c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT32: 52168c2ecf20Sopenharmony_ci def_op_bytes = def_ad_bytes = 4; 52178c2ecf20Sopenharmony_ci break; 52188c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 52198c2ecf20Sopenharmony_ci case X86EMUL_MODE_PROT64: 52208c2ecf20Sopenharmony_ci def_op_bytes = 4; 52218c2ecf20Sopenharmony_ci def_ad_bytes = 8; 52228c2ecf20Sopenharmony_ci break; 52238c2ecf20Sopenharmony_ci#endif 52248c2ecf20Sopenharmony_ci default: 52258c2ecf20Sopenharmony_ci return EMULATION_FAILED; 52268c2ecf20Sopenharmony_ci } 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci ctxt->op_bytes = def_op_bytes; 52298c2ecf20Sopenharmony_ci ctxt->ad_bytes = def_ad_bytes; 52308c2ecf20Sopenharmony_ci 52318c2ecf20Sopenharmony_ci /* Legacy prefixes. */ 52328c2ecf20Sopenharmony_ci for (;;) { 52338c2ecf20Sopenharmony_ci switch (ctxt->b = insn_fetch(u8, ctxt)) { 52348c2ecf20Sopenharmony_ci case 0x66: /* operand-size override */ 52358c2ecf20Sopenharmony_ci op_prefix = true; 52368c2ecf20Sopenharmony_ci /* switch between 2/4 bytes */ 52378c2ecf20Sopenharmony_ci ctxt->op_bytes = def_op_bytes ^ 6; 52388c2ecf20Sopenharmony_ci break; 52398c2ecf20Sopenharmony_ci case 0x67: /* address-size override */ 52408c2ecf20Sopenharmony_ci if (mode == X86EMUL_MODE_PROT64) 52418c2ecf20Sopenharmony_ci /* switch between 4/8 bytes */ 52428c2ecf20Sopenharmony_ci ctxt->ad_bytes = def_ad_bytes ^ 12; 52438c2ecf20Sopenharmony_ci else 52448c2ecf20Sopenharmony_ci /* switch between 2/4 bytes */ 52458c2ecf20Sopenharmony_ci ctxt->ad_bytes = def_ad_bytes ^ 6; 52468c2ecf20Sopenharmony_ci break; 52478c2ecf20Sopenharmony_ci case 0x26: /* ES override */ 52488c2ecf20Sopenharmony_ci has_seg_override = true; 52498c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_ES; 52508c2ecf20Sopenharmony_ci break; 52518c2ecf20Sopenharmony_ci case 0x2e: /* CS override */ 52528c2ecf20Sopenharmony_ci has_seg_override = true; 52538c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_CS; 52548c2ecf20Sopenharmony_ci break; 52558c2ecf20Sopenharmony_ci case 0x36: /* SS override */ 52568c2ecf20Sopenharmony_ci has_seg_override = true; 52578c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_SS; 52588c2ecf20Sopenharmony_ci break; 52598c2ecf20Sopenharmony_ci case 0x3e: /* DS override */ 52608c2ecf20Sopenharmony_ci has_seg_override = true; 52618c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_DS; 52628c2ecf20Sopenharmony_ci break; 52638c2ecf20Sopenharmony_ci case 0x64: /* FS override */ 52648c2ecf20Sopenharmony_ci has_seg_override = true; 52658c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_FS; 52668c2ecf20Sopenharmony_ci break; 52678c2ecf20Sopenharmony_ci case 0x65: /* GS override */ 52688c2ecf20Sopenharmony_ci has_seg_override = true; 52698c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_GS; 52708c2ecf20Sopenharmony_ci break; 52718c2ecf20Sopenharmony_ci case 0x40 ... 0x4f: /* REX */ 52728c2ecf20Sopenharmony_ci if (mode != X86EMUL_MODE_PROT64) 52738c2ecf20Sopenharmony_ci goto done_prefixes; 52748c2ecf20Sopenharmony_ci ctxt->rex_prefix = ctxt->b; 52758c2ecf20Sopenharmony_ci continue; 52768c2ecf20Sopenharmony_ci case 0xf0: /* LOCK */ 52778c2ecf20Sopenharmony_ci ctxt->lock_prefix = 1; 52788c2ecf20Sopenharmony_ci break; 52798c2ecf20Sopenharmony_ci case 0xf2: /* REPNE/REPNZ */ 52808c2ecf20Sopenharmony_ci case 0xf3: /* REP/REPE/REPZ */ 52818c2ecf20Sopenharmony_ci ctxt->rep_prefix = ctxt->b; 52828c2ecf20Sopenharmony_ci break; 52838c2ecf20Sopenharmony_ci default: 52848c2ecf20Sopenharmony_ci goto done_prefixes; 52858c2ecf20Sopenharmony_ci } 52868c2ecf20Sopenharmony_ci 52878c2ecf20Sopenharmony_ci /* Any legacy prefix after a REX prefix nullifies its effect. */ 52888c2ecf20Sopenharmony_ci 52898c2ecf20Sopenharmony_ci ctxt->rex_prefix = 0; 52908c2ecf20Sopenharmony_ci } 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_cidone_prefixes: 52938c2ecf20Sopenharmony_ci 52948c2ecf20Sopenharmony_ci /* REX prefix. */ 52958c2ecf20Sopenharmony_ci if (ctxt->rex_prefix & 8) 52968c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; /* REX.W */ 52978c2ecf20Sopenharmony_ci 52988c2ecf20Sopenharmony_ci /* Opcode byte(s). */ 52998c2ecf20Sopenharmony_ci opcode = opcode_table[ctxt->b]; 53008c2ecf20Sopenharmony_ci /* Two-byte opcode? */ 53018c2ecf20Sopenharmony_ci if (ctxt->b == 0x0f) { 53028c2ecf20Sopenharmony_ci ctxt->opcode_len = 2; 53038c2ecf20Sopenharmony_ci ctxt->b = insn_fetch(u8, ctxt); 53048c2ecf20Sopenharmony_ci opcode = twobyte_table[ctxt->b]; 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci /* 0F_38 opcode map */ 53078c2ecf20Sopenharmony_ci if (ctxt->b == 0x38) { 53088c2ecf20Sopenharmony_ci ctxt->opcode_len = 3; 53098c2ecf20Sopenharmony_ci ctxt->b = insn_fetch(u8, ctxt); 53108c2ecf20Sopenharmony_ci opcode = opcode_map_0f_38[ctxt->b]; 53118c2ecf20Sopenharmony_ci } 53128c2ecf20Sopenharmony_ci } 53138c2ecf20Sopenharmony_ci ctxt->d = opcode.flags; 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_ci if (ctxt->d & ModRM) 53168c2ecf20Sopenharmony_ci ctxt->modrm = insn_fetch(u8, ctxt); 53178c2ecf20Sopenharmony_ci 53188c2ecf20Sopenharmony_ci /* vex-prefix instructions are not implemented */ 53198c2ecf20Sopenharmony_ci if (ctxt->opcode_len == 1 && (ctxt->b == 0xc5 || ctxt->b == 0xc4) && 53208c2ecf20Sopenharmony_ci (mode == X86EMUL_MODE_PROT64 || (ctxt->modrm & 0xc0) == 0xc0)) { 53218c2ecf20Sopenharmony_ci ctxt->d = NotImpl; 53228c2ecf20Sopenharmony_ci } 53238c2ecf20Sopenharmony_ci 53248c2ecf20Sopenharmony_ci while (ctxt->d & GroupMask) { 53258c2ecf20Sopenharmony_ci switch (ctxt->d & GroupMask) { 53268c2ecf20Sopenharmony_ci case Group: 53278c2ecf20Sopenharmony_ci goffset = (ctxt->modrm >> 3) & 7; 53288c2ecf20Sopenharmony_ci opcode = opcode.u.group[goffset]; 53298c2ecf20Sopenharmony_ci break; 53308c2ecf20Sopenharmony_ci case GroupDual: 53318c2ecf20Sopenharmony_ci goffset = (ctxt->modrm >> 3) & 7; 53328c2ecf20Sopenharmony_ci if ((ctxt->modrm >> 6) == 3) 53338c2ecf20Sopenharmony_ci opcode = opcode.u.gdual->mod3[goffset]; 53348c2ecf20Sopenharmony_ci else 53358c2ecf20Sopenharmony_ci opcode = opcode.u.gdual->mod012[goffset]; 53368c2ecf20Sopenharmony_ci break; 53378c2ecf20Sopenharmony_ci case RMExt: 53388c2ecf20Sopenharmony_ci goffset = ctxt->modrm & 7; 53398c2ecf20Sopenharmony_ci opcode = opcode.u.group[goffset]; 53408c2ecf20Sopenharmony_ci break; 53418c2ecf20Sopenharmony_ci case Prefix: 53428c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && op_prefix) 53438c2ecf20Sopenharmony_ci return EMULATION_FAILED; 53448c2ecf20Sopenharmony_ci simd_prefix = op_prefix ? 0x66 : ctxt->rep_prefix; 53458c2ecf20Sopenharmony_ci switch (simd_prefix) { 53468c2ecf20Sopenharmony_ci case 0x00: opcode = opcode.u.gprefix->pfx_no; break; 53478c2ecf20Sopenharmony_ci case 0x66: opcode = opcode.u.gprefix->pfx_66; break; 53488c2ecf20Sopenharmony_ci case 0xf2: opcode = opcode.u.gprefix->pfx_f2; break; 53498c2ecf20Sopenharmony_ci case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break; 53508c2ecf20Sopenharmony_ci } 53518c2ecf20Sopenharmony_ci break; 53528c2ecf20Sopenharmony_ci case Escape: 53538c2ecf20Sopenharmony_ci if (ctxt->modrm > 0xbf) { 53548c2ecf20Sopenharmony_ci size_t size = ARRAY_SIZE(opcode.u.esc->high); 53558c2ecf20Sopenharmony_ci u32 index = array_index_nospec( 53568c2ecf20Sopenharmony_ci ctxt->modrm - 0xc0, size); 53578c2ecf20Sopenharmony_ci 53588c2ecf20Sopenharmony_ci opcode = opcode.u.esc->high[index]; 53598c2ecf20Sopenharmony_ci } else { 53608c2ecf20Sopenharmony_ci opcode = opcode.u.esc->op[(ctxt->modrm >> 3) & 7]; 53618c2ecf20Sopenharmony_ci } 53628c2ecf20Sopenharmony_ci break; 53638c2ecf20Sopenharmony_ci case InstrDual: 53648c2ecf20Sopenharmony_ci if ((ctxt->modrm >> 6) == 3) 53658c2ecf20Sopenharmony_ci opcode = opcode.u.idual->mod3; 53668c2ecf20Sopenharmony_ci else 53678c2ecf20Sopenharmony_ci opcode = opcode.u.idual->mod012; 53688c2ecf20Sopenharmony_ci break; 53698c2ecf20Sopenharmony_ci case ModeDual: 53708c2ecf20Sopenharmony_ci if (ctxt->mode == X86EMUL_MODE_PROT64) 53718c2ecf20Sopenharmony_ci opcode = opcode.u.mdual->mode64; 53728c2ecf20Sopenharmony_ci else 53738c2ecf20Sopenharmony_ci opcode = opcode.u.mdual->mode32; 53748c2ecf20Sopenharmony_ci break; 53758c2ecf20Sopenharmony_ci default: 53768c2ecf20Sopenharmony_ci return EMULATION_FAILED; 53778c2ecf20Sopenharmony_ci } 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci ctxt->d &= ~(u64)GroupMask; 53808c2ecf20Sopenharmony_ci ctxt->d |= opcode.flags; 53818c2ecf20Sopenharmony_ci } 53828c2ecf20Sopenharmony_ci 53838c2ecf20Sopenharmony_ci /* Unrecognised? */ 53848c2ecf20Sopenharmony_ci if (ctxt->d == 0) 53858c2ecf20Sopenharmony_ci return EMULATION_FAILED; 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_ci ctxt->execute = opcode.u.execute; 53888c2ecf20Sopenharmony_ci 53898c2ecf20Sopenharmony_ci if (unlikely(ctxt->ud) && likely(!(ctxt->d & EmulateOnUD))) 53908c2ecf20Sopenharmony_ci return EMULATION_FAILED; 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_ci if (unlikely(ctxt->d & 53938c2ecf20Sopenharmony_ci (NotImpl|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm|NearBranch| 53948c2ecf20Sopenharmony_ci No16))) { 53958c2ecf20Sopenharmony_ci /* 53968c2ecf20Sopenharmony_ci * These are copied unconditionally here, and checked unconditionally 53978c2ecf20Sopenharmony_ci * in x86_emulate_insn. 53988c2ecf20Sopenharmony_ci */ 53998c2ecf20Sopenharmony_ci ctxt->check_perm = opcode.check_perm; 54008c2ecf20Sopenharmony_ci ctxt->intercept = opcode.intercept; 54018c2ecf20Sopenharmony_ci 54028c2ecf20Sopenharmony_ci if (ctxt->d & NotImpl) 54038c2ecf20Sopenharmony_ci return EMULATION_FAILED; 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_ci if (mode == X86EMUL_MODE_PROT64) { 54068c2ecf20Sopenharmony_ci if (ctxt->op_bytes == 4 && (ctxt->d & Stack)) 54078c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 54088c2ecf20Sopenharmony_ci else if (ctxt->d & NearBranch) 54098c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 54108c2ecf20Sopenharmony_ci } 54118c2ecf20Sopenharmony_ci 54128c2ecf20Sopenharmony_ci if (ctxt->d & Op3264) { 54138c2ecf20Sopenharmony_ci if (mode == X86EMUL_MODE_PROT64) 54148c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 54158c2ecf20Sopenharmony_ci else 54168c2ecf20Sopenharmony_ci ctxt->op_bytes = 4; 54178c2ecf20Sopenharmony_ci } 54188c2ecf20Sopenharmony_ci 54198c2ecf20Sopenharmony_ci if ((ctxt->d & No16) && ctxt->op_bytes == 2) 54208c2ecf20Sopenharmony_ci ctxt->op_bytes = 4; 54218c2ecf20Sopenharmony_ci 54228c2ecf20Sopenharmony_ci if (ctxt->d & Sse) 54238c2ecf20Sopenharmony_ci ctxt->op_bytes = 16; 54248c2ecf20Sopenharmony_ci else if (ctxt->d & Mmx) 54258c2ecf20Sopenharmony_ci ctxt->op_bytes = 8; 54268c2ecf20Sopenharmony_ci } 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci /* ModRM and SIB bytes. */ 54298c2ecf20Sopenharmony_ci if (ctxt->d & ModRM) { 54308c2ecf20Sopenharmony_ci rc = decode_modrm(ctxt, &ctxt->memop); 54318c2ecf20Sopenharmony_ci if (!has_seg_override) { 54328c2ecf20Sopenharmony_ci has_seg_override = true; 54338c2ecf20Sopenharmony_ci ctxt->seg_override = ctxt->modrm_seg; 54348c2ecf20Sopenharmony_ci } 54358c2ecf20Sopenharmony_ci } else if (ctxt->d & MemAbs) 54368c2ecf20Sopenharmony_ci rc = decode_abs(ctxt, &ctxt->memop); 54378c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 54388c2ecf20Sopenharmony_ci goto done; 54398c2ecf20Sopenharmony_ci 54408c2ecf20Sopenharmony_ci if (!has_seg_override) 54418c2ecf20Sopenharmony_ci ctxt->seg_override = VCPU_SREG_DS; 54428c2ecf20Sopenharmony_ci 54438c2ecf20Sopenharmony_ci ctxt->memop.addr.mem.seg = ctxt->seg_override; 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_ci /* 54468c2ecf20Sopenharmony_ci * Decode and fetch the source operand: register, memory 54478c2ecf20Sopenharmony_ci * or immediate. 54488c2ecf20Sopenharmony_ci */ 54498c2ecf20Sopenharmony_ci rc = decode_operand(ctxt, &ctxt->src, (ctxt->d >> SrcShift) & OpMask); 54508c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 54518c2ecf20Sopenharmony_ci goto done; 54528c2ecf20Sopenharmony_ci 54538c2ecf20Sopenharmony_ci /* 54548c2ecf20Sopenharmony_ci * Decode and fetch the second source operand: register, memory 54558c2ecf20Sopenharmony_ci * or immediate. 54568c2ecf20Sopenharmony_ci */ 54578c2ecf20Sopenharmony_ci rc = decode_operand(ctxt, &ctxt->src2, (ctxt->d >> Src2Shift) & OpMask); 54588c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 54598c2ecf20Sopenharmony_ci goto done; 54608c2ecf20Sopenharmony_ci 54618c2ecf20Sopenharmony_ci /* Decode and fetch the destination operand: register or memory. */ 54628c2ecf20Sopenharmony_ci rc = decode_operand(ctxt, &ctxt->dst, (ctxt->d >> DstShift) & OpMask); 54638c2ecf20Sopenharmony_ci 54648c2ecf20Sopenharmony_ci if (ctxt->rip_relative && likely(ctxt->memopp)) 54658c2ecf20Sopenharmony_ci ctxt->memopp->addr.mem.ea = address_mask(ctxt, 54668c2ecf20Sopenharmony_ci ctxt->memopp->addr.mem.ea + ctxt->_eip); 54678c2ecf20Sopenharmony_ci 54688c2ecf20Sopenharmony_cidone: 54698c2ecf20Sopenharmony_ci if (rc == X86EMUL_PROPAGATE_FAULT) 54708c2ecf20Sopenharmony_ci ctxt->have_exception = true; 54718c2ecf20Sopenharmony_ci return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK; 54728c2ecf20Sopenharmony_ci} 54738c2ecf20Sopenharmony_ci 54748c2ecf20Sopenharmony_cibool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt) 54758c2ecf20Sopenharmony_ci{ 54768c2ecf20Sopenharmony_ci return ctxt->d & PageTable; 54778c2ecf20Sopenharmony_ci} 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_cistatic bool string_insn_completed(struct x86_emulate_ctxt *ctxt) 54808c2ecf20Sopenharmony_ci{ 54818c2ecf20Sopenharmony_ci /* The second termination condition only applies for REPE 54828c2ecf20Sopenharmony_ci * and REPNE. Test if the repeat string operation prefix is 54838c2ecf20Sopenharmony_ci * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the 54848c2ecf20Sopenharmony_ci * corresponding termination condition according to: 54858c2ecf20Sopenharmony_ci * - if REPE/REPZ and ZF = 0 then done 54868c2ecf20Sopenharmony_ci * - if REPNE/REPNZ and ZF = 1 then done 54878c2ecf20Sopenharmony_ci */ 54888c2ecf20Sopenharmony_ci if (((ctxt->b == 0xa6) || (ctxt->b == 0xa7) || 54898c2ecf20Sopenharmony_ci (ctxt->b == 0xae) || (ctxt->b == 0xaf)) 54908c2ecf20Sopenharmony_ci && (((ctxt->rep_prefix == REPE_PREFIX) && 54918c2ecf20Sopenharmony_ci ((ctxt->eflags & X86_EFLAGS_ZF) == 0)) 54928c2ecf20Sopenharmony_ci || ((ctxt->rep_prefix == REPNE_PREFIX) && 54938c2ecf20Sopenharmony_ci ((ctxt->eflags & X86_EFLAGS_ZF) == X86_EFLAGS_ZF)))) 54948c2ecf20Sopenharmony_ci return true; 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci return false; 54978c2ecf20Sopenharmony_ci} 54988c2ecf20Sopenharmony_ci 54998c2ecf20Sopenharmony_cistatic int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt) 55008c2ecf20Sopenharmony_ci{ 55018c2ecf20Sopenharmony_ci int rc; 55028c2ecf20Sopenharmony_ci 55038c2ecf20Sopenharmony_ci emulator_get_fpu(); 55048c2ecf20Sopenharmony_ci rc = asm_safe("fwait"); 55058c2ecf20Sopenharmony_ci emulator_put_fpu(); 55068c2ecf20Sopenharmony_ci 55078c2ecf20Sopenharmony_ci if (unlikely(rc != X86EMUL_CONTINUE)) 55088c2ecf20Sopenharmony_ci return emulate_exception(ctxt, MF_VECTOR, 0, false); 55098c2ecf20Sopenharmony_ci 55108c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 55118c2ecf20Sopenharmony_ci} 55128c2ecf20Sopenharmony_ci 55138c2ecf20Sopenharmony_cistatic void fetch_possible_mmx_operand(struct operand *op) 55148c2ecf20Sopenharmony_ci{ 55158c2ecf20Sopenharmony_ci if (op->type == OP_MM) 55168c2ecf20Sopenharmony_ci read_mmx_reg(&op->mm_val, op->addr.mm); 55178c2ecf20Sopenharmony_ci} 55188c2ecf20Sopenharmony_ci 55198c2ecf20Sopenharmony_cistatic int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop) 55208c2ecf20Sopenharmony_ci{ 55218c2ecf20Sopenharmony_ci ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF; 55228c2ecf20Sopenharmony_ci 55238c2ecf20Sopenharmony_ci if (!(ctxt->d & ByteOp)) 55248c2ecf20Sopenharmony_ci fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE; 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_ci asm("push %[flags]; popf; " CALL_NOSPEC " ; pushf; pop %[flags]\n" 55278c2ecf20Sopenharmony_ci : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags), 55288c2ecf20Sopenharmony_ci [thunk_target]"+S"(fop), ASM_CALL_CONSTRAINT 55298c2ecf20Sopenharmony_ci : "c"(ctxt->src2.val)); 55308c2ecf20Sopenharmony_ci 55318c2ecf20Sopenharmony_ci ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK); 55328c2ecf20Sopenharmony_ci if (!fop) /* exception is returned in fop variable */ 55338c2ecf20Sopenharmony_ci return emulate_de(ctxt); 55348c2ecf20Sopenharmony_ci return X86EMUL_CONTINUE; 55358c2ecf20Sopenharmony_ci} 55368c2ecf20Sopenharmony_ci 55378c2ecf20Sopenharmony_civoid init_decode_cache(struct x86_emulate_ctxt *ctxt) 55388c2ecf20Sopenharmony_ci{ 55398c2ecf20Sopenharmony_ci memset(&ctxt->rip_relative, 0, 55408c2ecf20Sopenharmony_ci (void *)&ctxt->modrm - (void *)&ctxt->rip_relative); 55418c2ecf20Sopenharmony_ci 55428c2ecf20Sopenharmony_ci ctxt->io_read.pos = 0; 55438c2ecf20Sopenharmony_ci ctxt->io_read.end = 0; 55448c2ecf20Sopenharmony_ci ctxt->mem_read.end = 0; 55458c2ecf20Sopenharmony_ci} 55468c2ecf20Sopenharmony_ci 55478c2ecf20Sopenharmony_ciint x86_emulate_insn(struct x86_emulate_ctxt *ctxt) 55488c2ecf20Sopenharmony_ci{ 55498c2ecf20Sopenharmony_ci const struct x86_emulate_ops *ops = ctxt->ops; 55508c2ecf20Sopenharmony_ci int rc = X86EMUL_CONTINUE; 55518c2ecf20Sopenharmony_ci int saved_dst_type = ctxt->dst.type; 55528c2ecf20Sopenharmony_ci unsigned emul_flags; 55538c2ecf20Sopenharmony_ci 55548c2ecf20Sopenharmony_ci ctxt->mem_read.pos = 0; 55558c2ecf20Sopenharmony_ci 55568c2ecf20Sopenharmony_ci /* LOCK prefix is allowed only with some instructions */ 55578c2ecf20Sopenharmony_ci if (ctxt->lock_prefix && (!(ctxt->d & Lock) || ctxt->dst.type != OP_MEM)) { 55588c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 55598c2ecf20Sopenharmony_ci goto done; 55608c2ecf20Sopenharmony_ci } 55618c2ecf20Sopenharmony_ci 55628c2ecf20Sopenharmony_ci if ((ctxt->d & SrcMask) == SrcMemFAddr && ctxt->src.type != OP_MEM) { 55638c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 55648c2ecf20Sopenharmony_ci goto done; 55658c2ecf20Sopenharmony_ci } 55668c2ecf20Sopenharmony_ci 55678c2ecf20Sopenharmony_ci emul_flags = ctxt->ops->get_hflags(ctxt); 55688c2ecf20Sopenharmony_ci if (unlikely(ctxt->d & 55698c2ecf20Sopenharmony_ci (No64|Undefined|Sse|Mmx|Intercept|CheckPerm|Priv|Prot|String))) { 55708c2ecf20Sopenharmony_ci if ((ctxt->mode == X86EMUL_MODE_PROT64 && (ctxt->d & No64)) || 55718c2ecf20Sopenharmony_ci (ctxt->d & Undefined)) { 55728c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 55738c2ecf20Sopenharmony_ci goto done; 55748c2ecf20Sopenharmony_ci } 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_ci if (((ctxt->d & (Sse|Mmx)) && ((ops->get_cr(ctxt, 0) & X86_CR0_EM))) 55778c2ecf20Sopenharmony_ci || ((ctxt->d & Sse) && !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) { 55788c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 55798c2ecf20Sopenharmony_ci goto done; 55808c2ecf20Sopenharmony_ci } 55818c2ecf20Sopenharmony_ci 55828c2ecf20Sopenharmony_ci if ((ctxt->d & (Sse|Mmx)) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) { 55838c2ecf20Sopenharmony_ci rc = emulate_nm(ctxt); 55848c2ecf20Sopenharmony_ci goto done; 55858c2ecf20Sopenharmony_ci } 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_ci if (ctxt->d & Mmx) { 55888c2ecf20Sopenharmony_ci rc = flush_pending_x87_faults(ctxt); 55898c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 55908c2ecf20Sopenharmony_ci goto done; 55918c2ecf20Sopenharmony_ci /* 55928c2ecf20Sopenharmony_ci * Now that we know the fpu is exception safe, we can fetch 55938c2ecf20Sopenharmony_ci * operands from it. 55948c2ecf20Sopenharmony_ci */ 55958c2ecf20Sopenharmony_ci fetch_possible_mmx_operand(&ctxt->src); 55968c2ecf20Sopenharmony_ci fetch_possible_mmx_operand(&ctxt->src2); 55978c2ecf20Sopenharmony_ci if (!(ctxt->d & Mov)) 55988c2ecf20Sopenharmony_ci fetch_possible_mmx_operand(&ctxt->dst); 55998c2ecf20Sopenharmony_ci } 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_ci if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && ctxt->intercept) { 56028c2ecf20Sopenharmony_ci rc = emulator_check_intercept(ctxt, ctxt->intercept, 56038c2ecf20Sopenharmony_ci X86_ICPT_PRE_EXCEPT); 56048c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56058c2ecf20Sopenharmony_ci goto done; 56068c2ecf20Sopenharmony_ci } 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_ci /* Instruction can only be executed in protected mode */ 56098c2ecf20Sopenharmony_ci if ((ctxt->d & Prot) && ctxt->mode < X86EMUL_MODE_PROT16) { 56108c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 56118c2ecf20Sopenharmony_ci goto done; 56128c2ecf20Sopenharmony_ci } 56138c2ecf20Sopenharmony_ci 56148c2ecf20Sopenharmony_ci /* Privileged instruction can be executed only in CPL=0 */ 56158c2ecf20Sopenharmony_ci if ((ctxt->d & Priv) && ops->cpl(ctxt)) { 56168c2ecf20Sopenharmony_ci if (ctxt->d & PrivUD) 56178c2ecf20Sopenharmony_ci rc = emulate_ud(ctxt); 56188c2ecf20Sopenharmony_ci else 56198c2ecf20Sopenharmony_ci rc = emulate_gp(ctxt, 0); 56208c2ecf20Sopenharmony_ci goto done; 56218c2ecf20Sopenharmony_ci } 56228c2ecf20Sopenharmony_ci 56238c2ecf20Sopenharmony_ci /* Do instruction specific permission checks */ 56248c2ecf20Sopenharmony_ci if (ctxt->d & CheckPerm) { 56258c2ecf20Sopenharmony_ci rc = ctxt->check_perm(ctxt); 56268c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56278c2ecf20Sopenharmony_ci goto done; 56288c2ecf20Sopenharmony_ci } 56298c2ecf20Sopenharmony_ci 56308c2ecf20Sopenharmony_ci if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { 56318c2ecf20Sopenharmony_ci rc = emulator_check_intercept(ctxt, ctxt->intercept, 56328c2ecf20Sopenharmony_ci X86_ICPT_POST_EXCEPT); 56338c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56348c2ecf20Sopenharmony_ci goto done; 56358c2ecf20Sopenharmony_ci } 56368c2ecf20Sopenharmony_ci 56378c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && (ctxt->d & String)) { 56388c2ecf20Sopenharmony_ci /* All REP prefixes have the same first termination condition */ 56398c2ecf20Sopenharmony_ci if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) { 56408c2ecf20Sopenharmony_ci string_registers_quirk(ctxt); 56418c2ecf20Sopenharmony_ci ctxt->eip = ctxt->_eip; 56428c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_RF; 56438c2ecf20Sopenharmony_ci goto done; 56448c2ecf20Sopenharmony_ci } 56458c2ecf20Sopenharmony_ci } 56468c2ecf20Sopenharmony_ci } 56478c2ecf20Sopenharmony_ci 56488c2ecf20Sopenharmony_ci if ((ctxt->src.type == OP_MEM) && !(ctxt->d & NoAccess)) { 56498c2ecf20Sopenharmony_ci rc = segmented_read(ctxt, ctxt->src.addr.mem, 56508c2ecf20Sopenharmony_ci ctxt->src.valptr, ctxt->src.bytes); 56518c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56528c2ecf20Sopenharmony_ci goto done; 56538c2ecf20Sopenharmony_ci ctxt->src.orig_val64 = ctxt->src.val64; 56548c2ecf20Sopenharmony_ci } 56558c2ecf20Sopenharmony_ci 56568c2ecf20Sopenharmony_ci if (ctxt->src2.type == OP_MEM) { 56578c2ecf20Sopenharmony_ci rc = segmented_read(ctxt, ctxt->src2.addr.mem, 56588c2ecf20Sopenharmony_ci &ctxt->src2.val, ctxt->src2.bytes); 56598c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56608c2ecf20Sopenharmony_ci goto done; 56618c2ecf20Sopenharmony_ci } 56628c2ecf20Sopenharmony_ci 56638c2ecf20Sopenharmony_ci if ((ctxt->d & DstMask) == ImplicitOps) 56648c2ecf20Sopenharmony_ci goto special_insn; 56658c2ecf20Sopenharmony_ci 56668c2ecf20Sopenharmony_ci 56678c2ecf20Sopenharmony_ci if ((ctxt->dst.type == OP_MEM) && !(ctxt->d & Mov)) { 56688c2ecf20Sopenharmony_ci /* optimisation - avoid slow emulated read if Mov */ 56698c2ecf20Sopenharmony_ci rc = segmented_read(ctxt, ctxt->dst.addr.mem, 56708c2ecf20Sopenharmony_ci &ctxt->dst.val, ctxt->dst.bytes); 56718c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) { 56728c2ecf20Sopenharmony_ci if (!(ctxt->d & NoWrite) && 56738c2ecf20Sopenharmony_ci rc == X86EMUL_PROPAGATE_FAULT && 56748c2ecf20Sopenharmony_ci ctxt->exception.vector == PF_VECTOR) 56758c2ecf20Sopenharmony_ci ctxt->exception.error_code |= PFERR_WRITE_MASK; 56768c2ecf20Sopenharmony_ci goto done; 56778c2ecf20Sopenharmony_ci } 56788c2ecf20Sopenharmony_ci } 56798c2ecf20Sopenharmony_ci /* Copy full 64-bit value for CMPXCHG8B. */ 56808c2ecf20Sopenharmony_ci ctxt->dst.orig_val64 = ctxt->dst.val64; 56818c2ecf20Sopenharmony_ci 56828c2ecf20Sopenharmony_cispecial_insn: 56838c2ecf20Sopenharmony_ci 56848c2ecf20Sopenharmony_ci if (unlikely(emul_flags & X86EMUL_GUEST_MASK) && (ctxt->d & Intercept)) { 56858c2ecf20Sopenharmony_ci rc = emulator_check_intercept(ctxt, ctxt->intercept, 56868c2ecf20Sopenharmony_ci X86_ICPT_POST_MEMACCESS); 56878c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 56888c2ecf20Sopenharmony_ci goto done; 56898c2ecf20Sopenharmony_ci } 56908c2ecf20Sopenharmony_ci 56918c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && (ctxt->d & String)) 56928c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_RF; 56938c2ecf20Sopenharmony_ci else 56948c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_RF; 56958c2ecf20Sopenharmony_ci 56968c2ecf20Sopenharmony_ci if (ctxt->execute) { 56978c2ecf20Sopenharmony_ci if (ctxt->d & Fastop) 56988c2ecf20Sopenharmony_ci rc = fastop(ctxt, ctxt->fop); 56998c2ecf20Sopenharmony_ci else 57008c2ecf20Sopenharmony_ci rc = ctxt->execute(ctxt); 57018c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 57028c2ecf20Sopenharmony_ci goto done; 57038c2ecf20Sopenharmony_ci goto writeback; 57048c2ecf20Sopenharmony_ci } 57058c2ecf20Sopenharmony_ci 57068c2ecf20Sopenharmony_ci if (ctxt->opcode_len == 2) 57078c2ecf20Sopenharmony_ci goto twobyte_insn; 57088c2ecf20Sopenharmony_ci else if (ctxt->opcode_len == 3) 57098c2ecf20Sopenharmony_ci goto threebyte_insn; 57108c2ecf20Sopenharmony_ci 57118c2ecf20Sopenharmony_ci switch (ctxt->b) { 57128c2ecf20Sopenharmony_ci case 0x70 ... 0x7f: /* jcc (short) */ 57138c2ecf20Sopenharmony_ci if (test_cc(ctxt->b, ctxt->eflags)) 57148c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, ctxt->src.val); 57158c2ecf20Sopenharmony_ci break; 57168c2ecf20Sopenharmony_ci case 0x8d: /* lea r16/r32, m */ 57178c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src.addr.mem.ea; 57188c2ecf20Sopenharmony_ci break; 57198c2ecf20Sopenharmony_ci case 0x90 ... 0x97: /* nop / xchg reg, rax */ 57208c2ecf20Sopenharmony_ci if (ctxt->dst.addr.reg == reg_rmw(ctxt, VCPU_REGS_RAX)) 57218c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; 57228c2ecf20Sopenharmony_ci else 57238c2ecf20Sopenharmony_ci rc = em_xchg(ctxt); 57248c2ecf20Sopenharmony_ci break; 57258c2ecf20Sopenharmony_ci case 0x98: /* cbw/cwde/cdqe */ 57268c2ecf20Sopenharmony_ci switch (ctxt->op_bytes) { 57278c2ecf20Sopenharmony_ci case 2: ctxt->dst.val = (s8)ctxt->dst.val; break; 57288c2ecf20Sopenharmony_ci case 4: ctxt->dst.val = (s16)ctxt->dst.val; break; 57298c2ecf20Sopenharmony_ci case 8: ctxt->dst.val = (s32)ctxt->dst.val; break; 57308c2ecf20Sopenharmony_ci } 57318c2ecf20Sopenharmony_ci break; 57328c2ecf20Sopenharmony_ci case 0xcc: /* int3 */ 57338c2ecf20Sopenharmony_ci rc = emulate_int(ctxt, 3); 57348c2ecf20Sopenharmony_ci break; 57358c2ecf20Sopenharmony_ci case 0xcd: /* int n */ 57368c2ecf20Sopenharmony_ci rc = emulate_int(ctxt, ctxt->src.val); 57378c2ecf20Sopenharmony_ci break; 57388c2ecf20Sopenharmony_ci case 0xce: /* into */ 57398c2ecf20Sopenharmony_ci if (ctxt->eflags & X86_EFLAGS_OF) 57408c2ecf20Sopenharmony_ci rc = emulate_int(ctxt, 4); 57418c2ecf20Sopenharmony_ci break; 57428c2ecf20Sopenharmony_ci case 0xe9: /* jmp rel */ 57438c2ecf20Sopenharmony_ci case 0xeb: /* jmp rel short */ 57448c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, ctxt->src.val); 57458c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; /* Disable writeback. */ 57468c2ecf20Sopenharmony_ci break; 57478c2ecf20Sopenharmony_ci case 0xf4: /* hlt */ 57488c2ecf20Sopenharmony_ci ctxt->ops->halt(ctxt); 57498c2ecf20Sopenharmony_ci break; 57508c2ecf20Sopenharmony_ci case 0xf5: /* cmc */ 57518c2ecf20Sopenharmony_ci /* complement carry flag from eflags reg */ 57528c2ecf20Sopenharmony_ci ctxt->eflags ^= X86_EFLAGS_CF; 57538c2ecf20Sopenharmony_ci break; 57548c2ecf20Sopenharmony_ci case 0xf8: /* clc */ 57558c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_CF; 57568c2ecf20Sopenharmony_ci break; 57578c2ecf20Sopenharmony_ci case 0xf9: /* stc */ 57588c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_CF; 57598c2ecf20Sopenharmony_ci break; 57608c2ecf20Sopenharmony_ci case 0xfc: /* cld */ 57618c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_DF; 57628c2ecf20Sopenharmony_ci break; 57638c2ecf20Sopenharmony_ci case 0xfd: /* std */ 57648c2ecf20Sopenharmony_ci ctxt->eflags |= X86_EFLAGS_DF; 57658c2ecf20Sopenharmony_ci break; 57668c2ecf20Sopenharmony_ci default: 57678c2ecf20Sopenharmony_ci goto cannot_emulate; 57688c2ecf20Sopenharmony_ci } 57698c2ecf20Sopenharmony_ci 57708c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 57718c2ecf20Sopenharmony_ci goto done; 57728c2ecf20Sopenharmony_ci 57738c2ecf20Sopenharmony_ciwriteback: 57748c2ecf20Sopenharmony_ci if (ctxt->d & SrcWrite) { 57758c2ecf20Sopenharmony_ci BUG_ON(ctxt->src.type == OP_MEM || ctxt->src.type == OP_MEM_STR); 57768c2ecf20Sopenharmony_ci rc = writeback(ctxt, &ctxt->src); 57778c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 57788c2ecf20Sopenharmony_ci goto done; 57798c2ecf20Sopenharmony_ci } 57808c2ecf20Sopenharmony_ci if (!(ctxt->d & NoWrite)) { 57818c2ecf20Sopenharmony_ci rc = writeback(ctxt, &ctxt->dst); 57828c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 57838c2ecf20Sopenharmony_ci goto done; 57848c2ecf20Sopenharmony_ci } 57858c2ecf20Sopenharmony_ci 57868c2ecf20Sopenharmony_ci /* 57878c2ecf20Sopenharmony_ci * restore dst type in case the decoding will be reused 57888c2ecf20Sopenharmony_ci * (happens for string instruction ) 57898c2ecf20Sopenharmony_ci */ 57908c2ecf20Sopenharmony_ci ctxt->dst.type = saved_dst_type; 57918c2ecf20Sopenharmony_ci 57928c2ecf20Sopenharmony_ci if ((ctxt->d & SrcMask) == SrcSI) 57938c2ecf20Sopenharmony_ci string_addr_inc(ctxt, VCPU_REGS_RSI, &ctxt->src); 57948c2ecf20Sopenharmony_ci 57958c2ecf20Sopenharmony_ci if ((ctxt->d & DstMask) == DstDI) 57968c2ecf20Sopenharmony_ci string_addr_inc(ctxt, VCPU_REGS_RDI, &ctxt->dst); 57978c2ecf20Sopenharmony_ci 57988c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && (ctxt->d & String)) { 57998c2ecf20Sopenharmony_ci unsigned int count; 58008c2ecf20Sopenharmony_ci struct read_cache *r = &ctxt->io_read; 58018c2ecf20Sopenharmony_ci if ((ctxt->d & SrcMask) == SrcSI) 58028c2ecf20Sopenharmony_ci count = ctxt->src.count; 58038c2ecf20Sopenharmony_ci else 58048c2ecf20Sopenharmony_ci count = ctxt->dst.count; 58058c2ecf20Sopenharmony_ci register_address_increment(ctxt, VCPU_REGS_RCX, -count); 58068c2ecf20Sopenharmony_ci 58078c2ecf20Sopenharmony_ci if (!string_insn_completed(ctxt)) { 58088c2ecf20Sopenharmony_ci /* 58098c2ecf20Sopenharmony_ci * Re-enter guest when pio read ahead buffer is empty 58108c2ecf20Sopenharmony_ci * or, if it is not used, after each 1024 iteration. 58118c2ecf20Sopenharmony_ci */ 58128c2ecf20Sopenharmony_ci if ((r->end != 0 || reg_read(ctxt, VCPU_REGS_RCX) & 0x3ff) && 58138c2ecf20Sopenharmony_ci (r->end == 0 || r->end != r->pos)) { 58148c2ecf20Sopenharmony_ci /* 58158c2ecf20Sopenharmony_ci * Reset read cache. Usually happens before 58168c2ecf20Sopenharmony_ci * decode, but since instruction is restarted 58178c2ecf20Sopenharmony_ci * we have to do it here. 58188c2ecf20Sopenharmony_ci */ 58198c2ecf20Sopenharmony_ci ctxt->mem_read.end = 0; 58208c2ecf20Sopenharmony_ci writeback_registers(ctxt); 58218c2ecf20Sopenharmony_ci return EMULATION_RESTART; 58228c2ecf20Sopenharmony_ci } 58238c2ecf20Sopenharmony_ci goto done; /* skip rip writeback */ 58248c2ecf20Sopenharmony_ci } 58258c2ecf20Sopenharmony_ci ctxt->eflags &= ~X86_EFLAGS_RF; 58268c2ecf20Sopenharmony_ci } 58278c2ecf20Sopenharmony_ci 58288c2ecf20Sopenharmony_ci ctxt->eip = ctxt->_eip; 58298c2ecf20Sopenharmony_ci if (ctxt->mode != X86EMUL_MODE_PROT64) 58308c2ecf20Sopenharmony_ci ctxt->eip = (u32)ctxt->_eip; 58318c2ecf20Sopenharmony_ci 58328c2ecf20Sopenharmony_cidone: 58338c2ecf20Sopenharmony_ci if (rc == X86EMUL_PROPAGATE_FAULT) { 58348c2ecf20Sopenharmony_ci WARN_ON(ctxt->exception.vector > 0x1f); 58358c2ecf20Sopenharmony_ci ctxt->have_exception = true; 58368c2ecf20Sopenharmony_ci } 58378c2ecf20Sopenharmony_ci if (rc == X86EMUL_INTERCEPTED) 58388c2ecf20Sopenharmony_ci return EMULATION_INTERCEPTED; 58398c2ecf20Sopenharmony_ci 58408c2ecf20Sopenharmony_ci if (rc == X86EMUL_CONTINUE) 58418c2ecf20Sopenharmony_ci writeback_registers(ctxt); 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_ci return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; 58448c2ecf20Sopenharmony_ci 58458c2ecf20Sopenharmony_citwobyte_insn: 58468c2ecf20Sopenharmony_ci switch (ctxt->b) { 58478c2ecf20Sopenharmony_ci case 0x09: /* wbinvd */ 58488c2ecf20Sopenharmony_ci (ctxt->ops->wbinvd)(ctxt); 58498c2ecf20Sopenharmony_ci break; 58508c2ecf20Sopenharmony_ci case 0x08: /* invd */ 58518c2ecf20Sopenharmony_ci case 0x0d: /* GrpP (prefetch) */ 58528c2ecf20Sopenharmony_ci case 0x18: /* Grp16 (prefetch/nop) */ 58538c2ecf20Sopenharmony_ci case 0x1f: /* nop */ 58548c2ecf20Sopenharmony_ci break; 58558c2ecf20Sopenharmony_ci case 0x20: /* mov cr, reg */ 58568c2ecf20Sopenharmony_ci ctxt->dst.val = ops->get_cr(ctxt, ctxt->modrm_reg); 58578c2ecf20Sopenharmony_ci break; 58588c2ecf20Sopenharmony_ci case 0x21: /* mov from dr to reg */ 58598c2ecf20Sopenharmony_ci ops->get_dr(ctxt, ctxt->modrm_reg, &ctxt->dst.val); 58608c2ecf20Sopenharmony_ci break; 58618c2ecf20Sopenharmony_ci case 0x40 ... 0x4f: /* cmov */ 58628c2ecf20Sopenharmony_ci if (test_cc(ctxt->b, ctxt->eflags)) 58638c2ecf20Sopenharmony_ci ctxt->dst.val = ctxt->src.val; 58648c2ecf20Sopenharmony_ci else if (ctxt->op_bytes != 4) 58658c2ecf20Sopenharmony_ci ctxt->dst.type = OP_NONE; /* no writeback */ 58668c2ecf20Sopenharmony_ci break; 58678c2ecf20Sopenharmony_ci case 0x80 ... 0x8f: /* jnz rel, etc*/ 58688c2ecf20Sopenharmony_ci if (test_cc(ctxt->b, ctxt->eflags)) 58698c2ecf20Sopenharmony_ci rc = jmp_rel(ctxt, ctxt->src.val); 58708c2ecf20Sopenharmony_ci break; 58718c2ecf20Sopenharmony_ci case 0x90 ... 0x9f: /* setcc r/m8 */ 58728c2ecf20Sopenharmony_ci ctxt->dst.val = test_cc(ctxt->b, ctxt->eflags); 58738c2ecf20Sopenharmony_ci break; 58748c2ecf20Sopenharmony_ci case 0xb6 ... 0xb7: /* movzx */ 58758c2ecf20Sopenharmony_ci ctxt->dst.bytes = ctxt->op_bytes; 58768c2ecf20Sopenharmony_ci ctxt->dst.val = (ctxt->src.bytes == 1) ? (u8) ctxt->src.val 58778c2ecf20Sopenharmony_ci : (u16) ctxt->src.val; 58788c2ecf20Sopenharmony_ci break; 58798c2ecf20Sopenharmony_ci case 0xbe ... 0xbf: /* movsx */ 58808c2ecf20Sopenharmony_ci ctxt->dst.bytes = ctxt->op_bytes; 58818c2ecf20Sopenharmony_ci ctxt->dst.val = (ctxt->src.bytes == 1) ? (s8) ctxt->src.val : 58828c2ecf20Sopenharmony_ci (s16) ctxt->src.val; 58838c2ecf20Sopenharmony_ci break; 58848c2ecf20Sopenharmony_ci default: 58858c2ecf20Sopenharmony_ci goto cannot_emulate; 58868c2ecf20Sopenharmony_ci } 58878c2ecf20Sopenharmony_ci 58888c2ecf20Sopenharmony_cithreebyte_insn: 58898c2ecf20Sopenharmony_ci 58908c2ecf20Sopenharmony_ci if (rc != X86EMUL_CONTINUE) 58918c2ecf20Sopenharmony_ci goto done; 58928c2ecf20Sopenharmony_ci 58938c2ecf20Sopenharmony_ci goto writeback; 58948c2ecf20Sopenharmony_ci 58958c2ecf20Sopenharmony_cicannot_emulate: 58968c2ecf20Sopenharmony_ci return EMULATION_FAILED; 58978c2ecf20Sopenharmony_ci} 58988c2ecf20Sopenharmony_ci 58998c2ecf20Sopenharmony_civoid emulator_invalidate_register_cache(struct x86_emulate_ctxt *ctxt) 59008c2ecf20Sopenharmony_ci{ 59018c2ecf20Sopenharmony_ci invalidate_registers(ctxt); 59028c2ecf20Sopenharmony_ci} 59038c2ecf20Sopenharmony_ci 59048c2ecf20Sopenharmony_civoid emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt) 59058c2ecf20Sopenharmony_ci{ 59068c2ecf20Sopenharmony_ci writeback_registers(ctxt); 59078c2ecf20Sopenharmony_ci} 59088c2ecf20Sopenharmony_ci 59098c2ecf20Sopenharmony_cibool emulator_can_use_gpa(struct x86_emulate_ctxt *ctxt) 59108c2ecf20Sopenharmony_ci{ 59118c2ecf20Sopenharmony_ci if (ctxt->rep_prefix && (ctxt->d & String)) 59128c2ecf20Sopenharmony_ci return false; 59138c2ecf20Sopenharmony_ci 59148c2ecf20Sopenharmony_ci if (ctxt->d & TwoMemOp) 59158c2ecf20Sopenharmony_ci return false; 59168c2ecf20Sopenharmony_ci 59178c2ecf20Sopenharmony_ci return true; 59188c2ecf20Sopenharmony_ci} 5919