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