Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hypercall.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * arch/x86/hypercall.c
3
 *
4
 * Common x86 hypercall infrastructure.
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Copyright (c) 2015,2016 Citrix Systems Ltd.
20
 */
21
22
#include <xen/hypercall.h>
23
24
#define ARGS(x, n)                              \
25
    [ __HYPERVISOR_ ## x ] = { n, n }
26
#define COMP(x, n, c)                           \
27
    [ __HYPERVISOR_ ## x ] = { n, c }
28
29
const hypercall_args_t hypercall_args_table[NR_hypercalls] =
30
{
31
    ARGS(set_trap_table, 1),
32
    ARGS(mmu_update, 4),
33
    ARGS(set_gdt, 2),
34
    ARGS(stack_switch, 2),
35
    COMP(set_callbacks, 3, 4),
36
    ARGS(fpu_taskswitch, 1),
37
    ARGS(sched_op_compat, 2),
38
    ARGS(platform_op, 1),
39
    ARGS(set_debugreg, 2),
40
    ARGS(get_debugreg, 1),
41
    COMP(update_descriptor, 2, 4),
42
    ARGS(memory_op, 2),
43
    ARGS(multicall, 2),
44
    COMP(update_va_mapping, 3, 4),
45
    COMP(set_timer_op, 1, 2),
46
    ARGS(event_channel_op_compat, 1),
47
    ARGS(xen_version, 2),
48
    ARGS(console_io, 3),
49
    ARGS(physdev_op_compat, 1),
50
    ARGS(grant_table_op, 3),
51
    ARGS(vm_assist, 2),
52
    COMP(update_va_mapping_otherdomain, 4, 5),
53
    ARGS(vcpu_op, 3),
54
    COMP(set_segment_base, 2, 0),
55
    ARGS(mmuext_op, 4),
56
    ARGS(xsm_op, 1),
57
    ARGS(nmi_op, 2),
58
    ARGS(sched_op, 2),
59
    ARGS(callback_op, 2),
60
    ARGS(xenoprof_op, 2),
61
    ARGS(event_channel_op, 2),
62
    ARGS(physdev_op, 2),
63
    ARGS(hvm_op, 2),
64
    ARGS(sysctl, 1),
65
    ARGS(domctl, 1),
66
    ARGS(kexec_op, 2),
67
    ARGS(tmem_op, 1),
68
    ARGS(xenpmu_op, 2),
69
    ARGS(dm_op, 3),
70
    ARGS(mca, 1),
71
    ARGS(arch_1, 1),
72
};
73
74
#undef COMP
75
#undef ARGS
76
77
0
#define next_arg(fmt, args) ({                                              \
78
0
    unsigned long __arg;                                                    \
79
0
    switch ( *(fmt)++ )                                                     \
80
0
    {                                                                       \
81
0
    case 'i': __arg = (unsigned long)va_arg(args, unsigned int);  break;    \
82
0
    case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break;    \
83
0
    case 'h': __arg = (unsigned long)va_arg(args, void *);        break;    \
84
0
    default:  __arg = 0; BUG();                                             \
85
0
    }                                                                       \
86
0
    __arg;                                                                  \
87
0
})
88
89
unsigned long hypercall_create_continuation(
90
    unsigned int op, const char *format, ...)
91
0
{
92
0
    struct vcpu *curr = current;
93
0
    struct mc_state *mcs = &curr->mc_state;
94
0
    const char *p = format;
95
0
    unsigned long arg;
96
0
    unsigned int i;
97
0
    va_list args;
98
0
99
0
    curr->hcall_preempted = true;
100
0
101
0
    va_start(args, format);
102
0
103
0
    if ( mcs->flags & MCSF_in_multicall )
104
0
    {
105
0
        for ( i = 0; *p != '\0'; i++ )
106
0
            mcs->call.args[i] = next_arg(p, args);
107
0
    }
108
0
    else
109
0
    {
110
0
        struct cpu_user_regs *regs = guest_cpu_user_regs();
111
0
112
0
        regs->rax = op;
113
0
114
0
        if ( !curr->hcall_compat )
115
0
        {
116
0
            for ( i = 0; *p != '\0'; i++ )
117
0
            {
118
0
                arg = next_arg(p, args);
119
0
                switch ( i )
120
0
                {
121
0
                case 0: regs->rdi = arg; break;
122
0
                case 1: regs->rsi = arg; break;
123
0
                case 2: regs->rdx = arg; break;
124
0
                case 3: regs->r10 = arg; break;
125
0
                case 4: regs->r8  = arg; break;
126
0
                case 5: regs->r9  = arg; break;
127
0
                }
128
0
            }
129
0
        }
130
0
        else
131
0
        {
132
0
            for ( i = 0; *p != '\0'; i++ )
133
0
            {
134
0
                arg = next_arg(p, args);
135
0
                switch ( i )
136
0
                {
137
0
                case 0: regs->rbx = arg; break;
138
0
                case 1: regs->rcx = arg; break;
139
0
                case 2: regs->rdx = arg; break;
140
0
                case 3: regs->rsi = arg; break;
141
0
                case 4: regs->rdi = arg; break;
142
0
                case 5: regs->rbp = arg; break;
143
0
                }
144
0
            }
145
0
        }
146
0
    }
147
0
148
0
    va_end(args);
149
0
150
0
    return op;
151
0
}
152
153
int hypercall_xlat_continuation(unsigned int *id, unsigned int nr,
154
                                unsigned int mask, ...)
155
0
{
156
0
    int rc = 0;
157
0
    struct mc_state *mcs = &current->mc_state;
158
0
    struct cpu_user_regs *regs;
159
0
    unsigned int i, cval = 0;
160
0
    unsigned long nval = 0;
161
0
    va_list args;
162
0
163
0
    ASSERT(nr <= ARRAY_SIZE(mcs->call.args));
164
0
    ASSERT(!(mask >> nr));
165
0
    ASSERT(!id || *id < nr);
166
0
    ASSERT(!id || !(mask & (1U << *id)));
167
0
168
0
    va_start(args, mask);
169
0
170
0
    if ( mcs->flags & MCSF_in_multicall )
171
0
    {
172
0
        if ( !current->hcall_preempted )
173
0
        {
174
0
            va_end(args);
175
0
            return 0;
176
0
        }
177
0
178
0
        for ( i = 0; i < nr; ++i, mask >>= 1 )
179
0
        {
180
0
            if ( mask & 1 )
181
0
            {
182
0
                nval = va_arg(args, unsigned long);
183
0
                cval = va_arg(args, unsigned int);
184
0
                if ( cval == nval )
185
0
                    mask &= ~1U;
186
0
                else
187
0
                    BUG_ON(nval == (unsigned int)nval);
188
0
            }
189
0
            else if ( id && *id == i )
190
0
            {
191
0
                *id = mcs->call.args[i];
192
0
                id = NULL;
193
0
            }
194
0
            if ( (mask & 1) && mcs->call.args[i] == nval )
195
0
            {
196
0
                mcs->call.args[i] = cval;
197
0
                ++rc;
198
0
            }
199
0
            else
200
0
                BUG_ON(mcs->call.args[i] != (unsigned int)mcs->call.args[i]);
201
0
        }
202
0
    }
203
0
    else
204
0
    {
205
0
        regs = guest_cpu_user_regs();
206
0
        for ( i = 0; i < nr; ++i, mask >>= 1 )
207
0
        {
208
0
            unsigned long *reg;
209
0
210
0
            switch ( i )
211
0
            {
212
0
            case 0: reg = &regs->rbx; break;
213
0
            case 1: reg = &regs->rcx; break;
214
0
            case 2: reg = &regs->rdx; break;
215
0
            case 3: reg = &regs->rsi; break;
216
0
            case 4: reg = &regs->rdi; break;
217
0
            case 5: reg = &regs->rbp; break;
218
0
            default: BUG(); reg = NULL; break;
219
0
            }
220
0
            if ( (mask & 1) )
221
0
            {
222
0
                nval = va_arg(args, unsigned long);
223
0
                cval = va_arg(args, unsigned int);
224
0
                if ( cval == nval )
225
0
                    mask &= ~1U;
226
0
                else
227
0
                    BUG_ON(nval == (unsigned int)nval);
228
0
            }
229
0
            else if ( id && *id == i )
230
0
            {
231
0
                *id = *reg;
232
0
                id = NULL;
233
0
            }
234
0
            if ( (mask & 1) && *reg == nval )
235
0
            {
236
0
                *reg = cval;
237
0
                ++rc;
238
0
            }
239
0
            else
240
0
                BUG_ON(*reg != (unsigned int)*reg);
241
0
        }
242
0
    }
243
0
244
0
    va_end(args);
245
0
246
0
    return rc;
247
0
}
248
249
/*
250
 * Local variables:
251
 * mode: C
252
 * c-file-style: "BSD"
253
 * c-basic-offset: 4
254
 * tab-width: 4
255
 * indent-tabs-mode: nil
256
 * End:
257
 */
258