1 /******************************************************************************
2  * arch/x86/pv/emulate.c
3  *
4  * Common PV emulation code
5  *
6  * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <xen/guest_access.h>
23 
24 #include <asm/debugreg.h>
25 
26 #include "emulate.h"
27 
pv_emul_read_descriptor(unsigned int sel,const struct vcpu * v,unsigned long * base,unsigned long * limit,unsigned int * ar,bool insn_fetch)28 int pv_emul_read_descriptor(unsigned int sel, const struct vcpu *v,
29                             unsigned long *base, unsigned long *limit,
30                             unsigned int *ar, bool insn_fetch)
31 {
32     seg_desc_t desc;
33 
34     if ( sel < 4 ||
35          /*
36           * Don't apply the GDT limit here, as the selector may be a Xen
37           * provided one. __get_user() will fail (without taking further
38           * action) for ones falling in the gap between guest populated
39           * and Xen ones.
40           */
41          ((sel & 4) && (sel >> 3) >= v->arch.pv.ldt_ents) )
42         desc.b = desc.a = 0;
43     else if ( __get_user(desc, gdt_ldt_desc_ptr(sel)) )
44         return 0;
45     if ( !insn_fetch )
46         desc.b &= ~_SEGMENT_L;
47 
48     *ar = desc.b & 0x00f0ff00;
49     if ( !(desc.b & _SEGMENT_L) )
50     {
51         *base = ((desc.a >> 16) + ((desc.b & 0xff) << 16) +
52                  (desc.b & 0xff000000));
53         *limit = (desc.a & 0xffff) | (desc.b & 0x000f0000);
54         if ( desc.b & _SEGMENT_G )
55             *limit = ((*limit + 1) << 12) - 1;
56 #ifndef NDEBUG
57         if ( sel > 3 )
58         {
59             unsigned int a, l;
60             unsigned char valid;
61 
62             asm volatile (
63                 "larl %2,%0 ; setz %1"
64                 : "=r" (a), "=qm" (valid) : "rm" (sel));
65             BUG_ON(valid && ((a & 0x00f0ff00) != *ar));
66             asm volatile (
67                 "lsll %2,%0 ; setz %1"
68                 : "=r" (l), "=qm" (valid) : "rm" (sel));
69             BUG_ON(valid && (l != *limit));
70         }
71 #endif
72     }
73     else
74     {
75         *base = 0UL;
76         *limit = ~0UL;
77     }
78 
79     return 1;
80 }
81 
pv_emul_instruction_done(struct cpu_user_regs * regs,unsigned long rip)82 void pv_emul_instruction_done(struct cpu_user_regs *regs, unsigned long rip)
83 {
84     regs->rip = rip;
85     regs->eflags &= ~X86_EFLAGS_RF;
86     if ( regs->eflags & X86_EFLAGS_TF )
87     {
88         current->arch.dr6 |= DR_STEP | DR_STATUS_RESERVED_ONE;
89         pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
90     }
91 }
92 
93 /*
94  * Local variables:
95  * mode: C
96  * c-file-style: "BSD"
97  * c-basic-offset: 4
98  * tab-width: 4
99  * indent-tabs-mode: nil
100  * End:
101  */
102