1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /******************************************************************************
3  * arch/x86/pv/emul-inv-op.c
4  *
5  * Emulate invalid op for PV guests
6  *
7  * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
8  */
9 
10 #include <asm/pv/trace.h>
11 
12 #include "emulate.h"
13 
emulate_forced_invalid_op(struct cpu_user_regs * regs)14 static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
15 {
16     char sig[5], instr[2];
17     unsigned long eip, rc;
18     struct cpuid_leaf res;
19     const struct vcpu_msrs *msrs = current->arch.msrs;
20 
21     eip = regs->rip;
22 
23     /* Check for forced emulation signature: ud2 ; .ascii "xen". */
24     if ( (rc = copy_from_guest_pv(sig, (char __user *)eip, sizeof(sig))) != 0 )
25     {
26         pv_inject_page_fault(0, eip + sizeof(sig) - rc);
27         return EXCRET_fault_fixed;
28     }
29     if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) )
30         return 0;
31     eip += sizeof(sig);
32 
33     /* We only emulate CPUID. */
34     if ( (rc = copy_from_guest_pv(instr, (char __user *)eip,
35                                   sizeof(instr))) != 0 )
36     {
37         pv_inject_page_fault(0, eip + sizeof(instr) - rc);
38         return EXCRET_fault_fixed;
39     }
40     if ( memcmp(instr, "\xf\xa2", sizeof(instr)) )
41         return 0;
42 
43     /* If cpuid faulting is enabled and CPL>0 inject a #GP in place of #UD. */
44     if ( msrs->misc_features_enables.cpuid_faulting &&
45          !guest_kernel_mode(current, regs) )
46     {
47         regs->rip = eip;
48         pv_inject_hw_exception(X86_EXC_GP, regs->error_code);
49         return EXCRET_fault_fixed;
50     }
51 
52     eip += sizeof(instr);
53 
54     guest_cpuid(current, regs->eax, regs->ecx, &res);
55 
56     regs->rax = res.a;
57     regs->rbx = res.b;
58     regs->rcx = res.c;
59     regs->rdx = res.d;
60 
61     pv_emul_instruction_done(regs, eip);
62 
63     trace_trap_one_addr(TRC_PV_FORCED_INVALID_OP, regs->rip);
64 
65     return EXCRET_fault_fixed;
66 }
67 
pv_emulate_invalid_op(struct cpu_user_regs * regs)68 bool pv_emulate_invalid_op(struct cpu_user_regs *regs)
69 {
70     return !emulate_forced_invalid_op(regs);
71 }
72 
73 /*
74  * Local variables:
75  * mode: C
76  * c-file-style: "BSD"
77  * c-basic-offset: 4
78  * tab-width: 4
79  * indent-tabs-mode: nil
80  * End:
81  */
82