1 /******************************************************************************
2  * arch/x86/pv/misc-hypercalls.c
3  *
4  * Misc hypercall handlers
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/hypercall.h>
23 
24 #include <asm/debugreg.h>
25 
do_set_debugreg(int reg,unsigned long value)26 long do_set_debugreg(int reg, unsigned long value)
27 {
28     return set_debugreg(current, reg, value);
29 }
30 
do_get_debugreg(int reg)31 unsigned long do_get_debugreg(int reg)
32 {
33     unsigned long val;
34     int res = x86emul_read_dr(reg, &val, NULL);
35 
36     return res == X86EMUL_OKAY ? val : -ENODEV;
37 }
38 
do_fpu_taskswitch(int set)39 long do_fpu_taskswitch(int set)
40 {
41     struct vcpu *v = current;
42 
43     if ( set )
44     {
45         v->arch.pv.ctrlreg[0] |= X86_CR0_TS;
46         stts();
47     }
48     else
49     {
50         v->arch.pv.ctrlreg[0] &= ~X86_CR0_TS;
51         if ( v->fpu_dirtied )
52             clts();
53     }
54 
55     return 0;
56 }
57 
58 /*
59  * Used by hypercalls and the emulator.
60  *  -ENODEV => #UD
61  *  -EINVAL => #GP Invalid bit
62  *  -EPERM  => #GP Valid bit, but not permitted to use
63  */
set_debugreg(struct vcpu * v,unsigned int reg,unsigned long value)64 long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
65 {
66     struct vcpu *curr = current;
67 
68     switch ( reg )
69     {
70     case 0 ... 3:
71         if ( !access_ok(value, sizeof(long)) )
72             return -EPERM;
73 
74         v->arch.dr[reg] = value;
75         if ( v == curr )
76         {
77             switch ( reg )
78             {
79             case 0: write_debugreg(0, value); break;
80             case 1: write_debugreg(1, value); break;
81             case 2: write_debugreg(2, value); break;
82             case 3: write_debugreg(3, value); break;
83             }
84         }
85         break;
86 
87     case 4:
88         if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
89             return -ENODEV;
90 
91         /* Fallthrough */
92     case 6:
93         /* The upper 32 bits are strictly reserved. */
94         if ( value != (uint32_t)value )
95             return -EINVAL;
96 
97         /*
98          * DR6: Bits 4-11,16-31 reserved (set to 1).
99          *      Bit 12 reserved (set to 0).
100          */
101         value &= ~DR_STATUS_RESERVED_ZERO; /* reserved bits => 0 */
102         value |=  DR_STATUS_RESERVED_ONE;  /* reserved bits => 1 */
103 
104         v->arch.dr6 = value;
105         if ( v == curr )
106             write_debugreg(6, value);
107         break;
108 
109     case 5:
110         if ( v->arch.pv.ctrlreg[4] & X86_CR4_DE )
111             return -ENODEV;
112 
113         /* Fallthrough */
114     case 7:
115         /* The upper 32 bits are strictly reserved. */
116         if ( value != (uint32_t)value )
117             return -EINVAL;
118 
119         /*
120          * DR7: Bit 10 reserved (set to 1).
121          *      Bits 11-12,14-15 reserved (set to 0).
122          */
123         value &= ~DR_CONTROL_RESERVED_ZERO; /* reserved bits => 0 */
124         value |=  DR_CONTROL_RESERVED_ONE;  /* reserved bits => 1 */
125         /*
126          * Privileged bits:
127          *      GD (bit 13): must be 0.
128          */
129         if ( value & DR_GENERAL_DETECT )
130             return -EPERM;
131 
132         /* DR7.{G,L}E = 0 => debugging disabled for this domain. */
133         if ( value & DR7_ACTIVE_MASK )
134         {
135             unsigned int i, io_enable = 0;
136 
137             for ( i = DR_CONTROL_SHIFT; i < 32; i += DR_CONTROL_SIZE )
138             {
139                 if ( ((value >> i) & 3) == DR_IO )
140                 {
141                     if ( !(v->arch.pv.ctrlreg[4] & X86_CR4_DE) )
142                         return -EPERM;
143                     io_enable |= value & (3 << ((i - 16) >> 1));
144                 }
145             }
146 
147             v->arch.pv.dr7_emul = io_enable;
148             value &= ~io_enable;
149 
150             /*
151              * If DR7 was previously clear then we need to load all other
152              * debug registers at this point as they were not restored during
153              * context switch.  Updating DR7 itself happens later.
154              */
155             if ( (v == curr) && !(v->arch.dr7 & DR7_ACTIVE_MASK) )
156                 activate_debugregs(v);
157         }
158         else
159             /* Zero the emulated controls if %dr7 isn't active. */
160             v->arch.pv.dr7_emul = 0;
161 
162         v->arch.dr7 = value;
163         if ( v == curr )
164             write_debugreg(7, value);
165         break;
166 
167     default:
168         return -ENODEV;
169     }
170 
171     return 0;
172 }
173 
174 /*
175  * Local variables:
176  * mode: C
177  * c-file-style: "BSD"
178  * c-basic-offset: 4
179  * tab-width: 4
180  * indent-tabs-mode: nil
181  * End:
182  */
183