~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to xen/arch/x86/hvm/vlapic.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * vlapic.c: virtualize LAPIC for HVM vcpus.
 
3
 *
 
4
 * Copyright (c) 2004, Intel Corporation.
 
5
 * Copyright (c) 2006 Keir Fraser, XenSource Inc.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify it
 
8
 * under the terms and conditions of the GNU General Public License,
 
9
 * version 2, as published by the Free Software Foundation.
 
10
 *
 
11
 * This program is distributed in the hope it will be useful, but WITHOUT
 
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License along with
 
17
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
18
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 
19
 */
 
20
 
 
21
#include <xen/config.h>
 
22
#include <xen/types.h>
 
23
#include <xen/mm.h>
 
24
#include <xen/xmalloc.h>
 
25
#include <xen/domain.h>
 
26
#include <xen/domain_page.h>
 
27
#include <xen/event.h>
 
28
#include <xen/trace.h>
 
29
#include <xen/lib.h>
 
30
#include <xen/sched.h>
 
31
#include <xen/numa.h>
 
32
#include <asm/current.h>
 
33
#include <asm/page.h>
 
34
#include <asm/hvm/hvm.h>
 
35
#include <asm/hvm/io.h>
 
36
#include <asm/hvm/support.h>
 
37
#include <asm/hvm/vmx/vmx.h>
 
38
#include <public/hvm/ioreq.h>
 
39
#include <public/hvm/params.h>
 
40
 
 
41
#define VLAPIC_VERSION                  0x00050014
 
42
#define VLAPIC_LVT_NUM                  6
 
43
 
 
44
/* vlapic's frequence is 100 MHz */
 
45
#define APIC_BUS_CYCLE_NS               10
 
46
 
 
47
#define LVT_MASK \
 
48
    APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
 
49
 
 
50
#define LINT_MASK   \
 
51
    LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
 
52
    APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
 
53
 
 
54
static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
 
55
{
 
56
     /* LVTT */
 
57
     LVT_MASK | APIC_LVT_TIMER_PERIODIC,
 
58
     /* LVTTHMR */
 
59
     LVT_MASK | APIC_MODE_MASK,
 
60
     /* LVTPC */
 
61
     LVT_MASK | APIC_MODE_MASK,
 
62
     /* LVT0-1 */
 
63
     LINT_MASK, LINT_MASK,
 
64
     /* LVTERR */
 
65
     LVT_MASK
 
66
};
 
67
 
 
68
/* Following could belong in apicdef.h */
 
69
#define APIC_SHORT_MASK                  0xc0000
 
70
#define APIC_DEST_NOSHORT                0x0
 
71
#define APIC_DEST_MASK                   0x800
 
72
 
 
73
#define vlapic_lvt_vector(vlapic, lvt_type)                     \
 
74
    (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
 
75
 
 
76
#define vlapic_lvt_dm(vlapic, lvt_type)                         \
 
77
    (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
 
78
 
 
79
#define vlapic_lvtt_period(vlapic)                              \
 
80
    (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
 
81
 
 
82
 
 
83
/*
 
84
 * Generic APIC bitmap vector update & search routines.
 
85
 */
 
86
 
 
87
#define VEC_POS(v) ((v)%32)
 
88
#define REG_POS(v) (((v)/32) * 0x10)
 
89
#define vlapic_test_and_set_vector(vec, bitmap)                         \
 
90
    test_and_set_bit(VEC_POS(vec),                                      \
 
91
                     (unsigned long *)((bitmap) + REG_POS(vec)))
 
92
#define vlapic_test_and_clear_vector(vec, bitmap)                       \
 
93
    test_and_clear_bit(VEC_POS(vec),                                    \
 
94
                       (unsigned long *)((bitmap) + REG_POS(vec)))
 
95
#define vlapic_set_vector(vec, bitmap)                                  \
 
96
    set_bit(VEC_POS(vec), (unsigned long *)((bitmap) + REG_POS(vec)))
 
97
#define vlapic_clear_vector(vec, bitmap)                                \
 
98
    clear_bit(VEC_POS(vec), (unsigned long *)((bitmap) + REG_POS(vec)))
 
99
 
 
100
static int vlapic_find_highest_vector(void *bitmap)
 
101
{
 
102
    uint32_t *word = bitmap;
 
103
    int word_offset = MAX_VECTOR / 32;
 
104
 
 
105
    /* Work backwards through the bitmap (first 32-bit word in every four). */
 
106
    while ( (word_offset != 0) && (word[(--word_offset)*4] == 0) )
 
107
        continue;
 
108
 
 
109
    return (fls(word[word_offset*4]) - 1) + (word_offset * 32);
 
110
}
 
111
 
 
112
 
 
113
/*
 
114
 * IRR-specific bitmap update & search routines.
 
115
 */
 
116
 
 
117
static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
 
118
{
 
119
    return vlapic_test_and_set_vector(vector, &vlapic->regs->data[APIC_IRR]);
 
120
}
 
121
 
 
122
static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
 
123
{
 
124
    vlapic_clear_vector(vector, &vlapic->regs->data[APIC_IRR]);
 
125
}
 
126
 
 
127
static int vlapic_find_highest_irr(struct vlapic *vlapic)
 
128
{
 
129
    return vlapic_find_highest_vector(&vlapic->regs->data[APIC_IRR]);
 
130
}
 
131
 
 
132
int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
 
133
{
 
134
    int ret;
 
135
 
 
136
    ret = !vlapic_test_and_set_irr(vec, vlapic);
 
137
    if ( trig )
 
138
        vlapic_set_vector(vec, &vlapic->regs->data[APIC_TMR]);
 
139
 
 
140
    /* We may need to wake up target vcpu, besides set pending bit here */
 
141
    return ret;
 
142
}
 
143
 
 
144
static int vlapic_find_highest_isr(struct vlapic *vlapic)
 
145
{
 
146
    return vlapic_find_highest_vector(&vlapic->regs->data[APIC_ISR]);
 
147
}
 
148
 
 
149
static uint32_t vlapic_get_ppr(struct vlapic *vlapic)
 
150
{
 
151
    uint32_t tpr, isrv, ppr;
 
152
    int isr;
 
153
 
 
154
    tpr  = vlapic_get_reg(vlapic, APIC_TASKPRI);
 
155
    isr  = vlapic_find_highest_isr(vlapic);
 
156
    isrv = (isr != -1) ? isr : 0;
 
157
 
 
158
    if ( (tpr & 0xf0) >= (isrv & 0xf0) )
 
159
        ppr = tpr & 0xff;
 
160
    else
 
161
        ppr = isrv & 0xf0;
 
162
 
 
163
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
 
164
                "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
 
165
                vlapic, ppr, isr, isrv);
 
166
 
 
167
    return ppr;
 
168
}
 
169
 
 
170
static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
 
171
{
 
172
    int result = 0;
 
173
    uint8_t logical_id;
 
174
 
 
175
    logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
 
176
 
 
177
    switch ( vlapic_get_reg(vlapic, APIC_DFR) )
 
178
    {
 
179
    case APIC_DFR_FLAT:
 
180
        if ( logical_id & mda )
 
181
            result = 1;
 
182
        break;
 
183
    case APIC_DFR_CLUSTER:
 
184
        if ( ((logical_id >> 4) == (mda >> 0x4)) && (logical_id & mda & 0xf) )
 
185
            result = 1;
 
186
        break;
 
187
    default:
 
188
        gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d: %08x\n",
 
189
                 vlapic_vcpu(vlapic)->vcpu_id,
 
190
                 vlapic_get_reg(vlapic, APIC_DFR));
 
191
        break;
 
192
    }
 
193
 
 
194
    return result;
 
195
}
 
196
 
 
197
bool_t vlapic_match_dest(
 
198
    struct vlapic *target, struct vlapic *source,
 
199
    int short_hand, uint8_t dest, uint8_t dest_mode)
 
200
{
 
201
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
 
202
                "dest_mode 0x%x, short_hand 0x%x",
 
203
                target, source, dest, dest_mode, short_hand);
 
204
 
 
205
    switch ( short_hand )
 
206
    {
 
207
    case APIC_DEST_NOSHORT:
 
208
        if ( dest_mode )
 
209
            return vlapic_match_logical_addr(target, dest);
 
210
        return ((dest == 0xFF) || (dest == VLAPIC_ID(target)));
 
211
 
 
212
    case APIC_DEST_SELF:
 
213
        return (target == source);
 
214
 
 
215
    case APIC_DEST_ALLINC:
 
216
        return 1;
 
217
 
 
218
    case APIC_DEST_ALLBUT:
 
219
        return (target != source);
 
220
 
 
221
    default:
 
222
        gdprintk(XENLOG_WARNING, "Bad dest shorthand value %x\n", short_hand);
 
223
        break;
 
224
    }
 
225
 
 
226
    return 0;
 
227
}
 
228
 
 
229
static int vlapic_vcpu_pause_async(struct vcpu *v)
 
230
{
 
231
    vcpu_pause_nosync(v);
 
232
 
 
233
    if ( v->is_running )
 
234
    {
 
235
        vcpu_unpause(v);
 
236
        return 0;
 
237
    }
 
238
 
 
239
    sync_vcpu_execstate(v);
 
240
    return 1;
 
241
}
 
242
 
 
243
static void vlapic_init_action(unsigned long _vcpu)
 
244
{
 
245
    struct vcpu *v = (struct vcpu *)_vcpu;
 
246
    struct domain *d = v->domain;
 
247
    bool_t fpu_initialised;
 
248
 
 
249
    /* If the VCPU is not on its way down we have nothing to do. */
 
250
    if ( !test_bit(_VPF_down, &v->pause_flags) )
 
251
        return;
 
252
 
 
253
    if ( !vlapic_vcpu_pause_async(v) )
 
254
    {
 
255
        tasklet_schedule(&vcpu_vlapic(v)->init_tasklet);
 
256
        return;
 
257
    }
 
258
 
 
259
    /* Reset necessary VCPU state. This does not include FPU state. */
 
260
    domain_lock(d);
 
261
    fpu_initialised = v->fpu_initialised;
 
262
    vcpu_reset(v);
 
263
    v->fpu_initialised = fpu_initialised;
 
264
    vlapic_reset(vcpu_vlapic(v));
 
265
    domain_unlock(d);
 
266
 
 
267
    vcpu_unpause(v);
 
268
}
 
269
 
 
270
static int vlapic_accept_init(struct vcpu *v)
 
271
{
 
272
    /* Nothing to do if the VCPU is already reset. */
 
273
    if ( !v->is_initialised )
 
274
        return X86EMUL_OKAY;
 
275
 
 
276
    /* Asynchronously take the VCPU down and schedule reset work. */
 
277
    hvm_vcpu_down(v);
 
278
    tasklet_schedule(&vcpu_vlapic(v)->init_tasklet);
 
279
    return X86EMUL_RETRY;
 
280
}
 
281
 
 
282
static int vlapic_accept_sipi(struct vcpu *v, int trampoline_vector)
 
283
{
 
284
    /* If the VCPU is not on its way down we have nothing to do. */
 
285
    if ( !test_bit(_VPF_down, &v->pause_flags) )
 
286
        return X86EMUL_OKAY;
 
287
 
 
288
    if ( !vlapic_vcpu_pause_async(v) )
 
289
        return X86EMUL_RETRY;
 
290
 
 
291
    hvm_vcpu_reset_state(v, trampoline_vector << 8, 0);
 
292
 
 
293
    vcpu_unpause(v);
 
294
 
 
295
    return X86EMUL_OKAY;
 
296
}
 
297
 
 
298
/* Add a pending IRQ into lapic. */
 
299
static int vlapic_accept_irq(struct vcpu *v, uint32_t icr_low)
 
300
{
 
301
    struct vlapic *vlapic = vcpu_vlapic(v);
 
302
    uint8_t vector = (uint8_t)icr_low;
 
303
    int rc = X86EMUL_OKAY;
 
304
 
 
305
    switch ( icr_low & APIC_MODE_MASK )
 
306
    {
 
307
    case APIC_DM_FIXED:
 
308
    case APIC_DM_LOWEST:
 
309
        if ( vlapic_enabled(vlapic) &&
 
310
             !vlapic_test_and_set_irr(vector, vlapic) )
 
311
            vcpu_kick(v);
 
312
        break;
 
313
 
 
314
    case APIC_DM_REMRD:
 
315
        gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3\n");
 
316
        break;
 
317
 
 
318
    case APIC_DM_SMI:
 
319
        gdprintk(XENLOG_WARNING, "Ignoring guest SMI\n");
 
320
        break;
 
321
 
 
322
    case APIC_DM_NMI:
 
323
        if ( !test_and_set_bool(v->nmi_pending) )
 
324
            vcpu_kick(v);
 
325
        break;
 
326
 
 
327
    case APIC_DM_INIT:
 
328
        /* No work on INIT de-assert for P4-type APIC. */
 
329
        if ( (icr_low & (APIC_INT_LEVELTRIG | APIC_INT_ASSERT)) ==
 
330
             APIC_INT_LEVELTRIG )
 
331
            break;
 
332
        rc = vlapic_accept_init(v);
 
333
        break;
 
334
 
 
335
    case APIC_DM_STARTUP:
 
336
        rc = vlapic_accept_sipi(v, vector);
 
337
        break;
 
338
 
 
339
    default:
 
340
        gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode in ICR %x\n",
 
341
                 icr_low);
 
342
        domain_crash(v->domain);
 
343
    }
 
344
 
 
345
    return rc;
 
346
}
 
347
 
 
348
struct vlapic *vlapic_lowest_prio(
 
349
    struct domain *d, struct vlapic *source,
 
350
    int short_hand, uint8_t dest, uint8_t dest_mode)
 
351
{
 
352
    int old = d->arch.hvm_domain.irq.round_robin_prev_vcpu;
 
353
    uint32_t ppr, target_ppr = UINT_MAX;
 
354
    struct vlapic *vlapic, *target = NULL;
 
355
    struct vcpu *v;
 
356
 
 
357
    if ( unlikely(!d->vcpu) || unlikely((v = d->vcpu[old]) == NULL) )
 
358
        return NULL;
 
359
 
 
360
    do {
 
361
        v = v->next_in_list ? : d->vcpu[0];
 
362
        vlapic = vcpu_vlapic(v);
 
363
        if ( vlapic_match_dest(vlapic, source, short_hand, dest, dest_mode) &&
 
364
             vlapic_enabled(vlapic) &&
 
365
             ((ppr = vlapic_get_ppr(vlapic)) < target_ppr) )
 
366
        {
 
367
            target = vlapic;
 
368
            target_ppr = ppr;
 
369
        }
 
370
    } while ( v->vcpu_id != old );
 
371
 
 
372
    if ( target != NULL )
 
373
        d->arch.hvm_domain.irq.round_robin_prev_vcpu =
 
374
            vlapic_vcpu(target)->vcpu_id;
 
375
 
 
376
    return target;
 
377
}
 
378
 
 
379
void vlapic_EOI_set(struct vlapic *vlapic)
 
380
{
 
381
    int vector = vlapic_find_highest_isr(vlapic);
 
382
 
 
383
    /* Some EOI writes may not have a matching to an in-service interrupt. */
 
384
    if ( vector == -1 )
 
385
        return;
 
386
 
 
387
    vlapic_clear_vector(vector, &vlapic->regs->data[APIC_ISR]);
 
388
 
 
389
    if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
 
390
        vioapic_update_EOI(vlapic_domain(vlapic), vector);
 
391
 
 
392
    hvm_dpci_msi_eoi(current->domain, vector);
 
393
}
 
394
 
 
395
int vlapic_ipi(
 
396
    struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
 
397
{
 
398
    unsigned int dest       = GET_xAPIC_DEST_FIELD(icr_high);
 
399
    unsigned int short_hand = icr_low & APIC_SHORT_MASK;
 
400
    unsigned int dest_mode  = !!(icr_low & APIC_DEST_MASK);
 
401
    struct vlapic *target;
 
402
    struct vcpu *v;
 
403
    int rc = X86EMUL_OKAY;
 
404
 
 
405
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low);
 
406
 
 
407
    if ( (icr_low & APIC_MODE_MASK) == APIC_DM_LOWEST )
 
408
    {
 
409
        target = vlapic_lowest_prio(vlapic_domain(vlapic), vlapic,
 
410
                                    short_hand, dest, dest_mode);
 
411
        if ( target != NULL )
 
412
            rc = vlapic_accept_irq(vlapic_vcpu(target), icr_low);
 
413
        return rc;
 
414
    }
 
415
 
 
416
    for_each_vcpu ( vlapic_domain(vlapic), v )
 
417
    {
 
418
        if ( vlapic_match_dest(vcpu_vlapic(v), vlapic,
 
419
                               short_hand, dest, dest_mode) )
 
420
                rc = vlapic_accept_irq(v, icr_low);
 
421
        if ( rc != X86EMUL_OKAY )
 
422
            break;
 
423
    }
 
424
 
 
425
    return rc;
 
426
}
 
427
 
 
428
static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
 
429
{
 
430
    struct vcpu *v = current;
 
431
    uint32_t tmcct, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
 
432
    uint64_t counter_passed;
 
433
 
 
434
    counter_passed = ((hvm_get_guest_time(v) - vlapic->timer_last_update)
 
435
                      / APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor);
 
436
    tmcct = tmict - counter_passed;
 
437
 
 
438
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
 
439
                "timer initial count %d, timer current count %d, "
 
440
                "offset %"PRId64,
 
441
                tmict, tmcct, counter_passed);
 
442
 
 
443
    return tmcct;
 
444
}
 
445
 
 
446
static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
 
447
{
 
448
    /* Only bits 0, 1 and 3 are settable; others are MBZ. */
 
449
    val &= 0xb;
 
450
    vlapic_set_reg(vlapic, APIC_TDCR, val);
 
451
 
 
452
    /* Update the demangled hw.timer_divisor. */
 
453
    val = ((val & 3) | ((val & 8) >> 1)) + 1;
 
454
    vlapic->hw.timer_divisor = 1 << (val & 7);
 
455
 
 
456
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
 
457
                "timer_divisor: %d", vlapic->hw.timer_divisor);
 
458
}
 
459
 
 
460
static void vlapic_read_aligned(
 
461
    struct vlapic *vlapic, unsigned int offset, unsigned int *result)
 
462
{
 
463
    switch ( offset )
 
464
    {
 
465
    case APIC_PROCPRI:
 
466
        *result = vlapic_get_ppr(vlapic);
 
467
        break;
 
468
 
 
469
    case APIC_TMCCT: /* Timer CCR */
 
470
        *result = vlapic_get_tmcct(vlapic);
 
471
        break;
 
472
 
 
473
    default:
 
474
        *result = vlapic_get_reg(vlapic, offset);
 
475
        break;
 
476
    }
 
477
}
 
478
 
 
479
static int vlapic_read(
 
480
    struct vcpu *v, unsigned long address,
 
481
    unsigned long len, unsigned long *pval)
 
482
{
 
483
    unsigned int alignment;
 
484
    unsigned int tmp;
 
485
    unsigned long result = 0;
 
486
    struct vlapic *vlapic = vcpu_vlapic(v);
 
487
    unsigned int offset = address - vlapic_base_address(vlapic);
 
488
 
 
489
    if ( offset > (APIC_TDCR + 0x3) )
 
490
        goto out;
 
491
 
 
492
    alignment = offset & 0x3;
 
493
 
 
494
    vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
 
495
    switch ( len )
 
496
    {
 
497
    case 1:
 
498
        result = *((unsigned char *)&tmp + alignment);
 
499
        break;
 
500
 
 
501
    case 2:
 
502
        if ( alignment == 3 )
 
503
            goto unaligned_exit_and_crash;
 
504
        result = *(unsigned short *)((unsigned char *)&tmp + alignment);
 
505
        break;
 
506
 
 
507
    case 4:
 
508
        if ( alignment != 0 )
 
509
            goto unaligned_exit_and_crash;
 
510
        result = *(unsigned int *)((unsigned char *)&tmp + alignment);
 
511
        break;
 
512
 
 
513
    default:
 
514
        gdprintk(XENLOG_ERR, "Local APIC read with len=0x%lx, "
 
515
                 "should be 4 instead.\n", len);
 
516
        goto exit_and_crash;
 
517
    }
 
518
 
 
519
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
 
520
                "and the result is 0x%lx", offset, len, result);
 
521
 
 
522
 out:
 
523
    *pval = result;
 
524
    return X86EMUL_OKAY;
 
525
 
 
526
 unaligned_exit_and_crash:
 
527
    gdprintk(XENLOG_ERR, "Unaligned LAPIC read len=0x%lx at offset=0x%x.\n",
 
528
             len, offset);
 
529
 exit_and_crash:
 
530
    domain_crash(v->domain);
 
531
    return X86EMUL_OKAY;
 
532
}
 
533
 
 
534
static void vlapic_pt_cb(struct vcpu *v, void *data)
 
535
{
 
536
    *(s_time_t *)data = hvm_get_guest_time(v);
 
537
}
 
538
 
 
539
static int vlapic_write(struct vcpu *v, unsigned long address,
 
540
                        unsigned long len, unsigned long val)
 
541
{
 
542
    struct vlapic *vlapic = vcpu_vlapic(v);
 
543
    unsigned int offset = address - vlapic_base_address(vlapic);
 
544
    int rc = X86EMUL_OKAY;
 
545
 
 
546
    if ( offset != 0xb0 )
 
547
        HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
 
548
                    "offset 0x%x with length 0x%lx, and value is 0x%lx",
 
549
                    offset, len, val);
 
550
 
 
551
    /*
 
552
     * According to the IA32 Manual, all accesses should be 32 bits.
 
553
     * Some OSes do 8- or 16-byte accesses, however.
 
554
     */
 
555
    val = (uint32_t)val;
 
556
    if ( len != 4 )
 
557
    {
 
558
        unsigned int tmp;
 
559
        unsigned char alignment;
 
560
 
 
561
        gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
 
562
 
 
563
        alignment = offset & 0x3;
 
564
        (void)vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
 
565
 
 
566
        switch ( len )
 
567
        {
 
568
        case 1:
 
569
            val = ((tmp & ~(0xff << (8*alignment))) |
 
570
                   ((val & 0xff) << (8*alignment)));
 
571
            break;
 
572
 
 
573
        case 2:
 
574
            if ( alignment & 1 )
 
575
                goto unaligned_exit_and_crash;
 
576
            val = ((tmp & ~(0xffff << (8*alignment))) |
 
577
                   ((val & 0xffff) << (8*alignment)));
 
578
            break;
 
579
 
 
580
        default:
 
581
            gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
 
582
                     "should be 4 instead\n", len);
 
583
            goto exit_and_crash;
 
584
        }
 
585
    }
 
586
    else if ( (offset & 0x3) != 0 )
 
587
        goto unaligned_exit_and_crash;
 
588
 
 
589
    offset &= ~0x3;
 
590
 
 
591
    switch ( offset )
 
592
    {
 
593
    case APIC_TASKPRI:
 
594
        vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
 
595
        break;
 
596
 
 
597
    case APIC_EOI:
 
598
        vlapic_EOI_set(vlapic);
 
599
        break;
 
600
 
 
601
    case APIC_LDR:
 
602
        vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
 
603
        break;
 
604
 
 
605
    case APIC_DFR:
 
606
        vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
 
607
        break;
 
608
 
 
609
    case APIC_SPIV:
 
610
        vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
 
611
 
 
612
        if ( !(val & APIC_SPIV_APIC_ENABLED) )
 
613
        {
 
614
            int i;
 
615
            uint32_t lvt_val;
 
616
 
 
617
            vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
 
618
 
 
619
            for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
 
620
            {
 
621
                lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
 
622
                vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
 
623
                               lvt_val | APIC_LVT_MASKED);
 
624
            }
 
625
        }
 
626
        else
 
627
        {
 
628
            vlapic->hw.disabled &= ~VLAPIC_SW_DISABLED;
 
629
            pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
 
630
        }
 
631
        break;
 
632
 
 
633
    case APIC_ESR:
 
634
        /* Nothing to do. */
 
635
        break;
 
636
 
 
637
    case APIC_ICR:
 
638
        val &= ~(1 << 12); /* always clear the pending bit */
 
639
        rc = vlapic_ipi(vlapic, val, vlapic_get_reg(vlapic, APIC_ICR2));
 
640
        if ( rc == X86EMUL_OKAY )
 
641
            vlapic_set_reg(vlapic, APIC_ICR, val);
 
642
        break;
 
643
 
 
644
    case APIC_ICR2:
 
645
        vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
 
646
        break;
 
647
 
 
648
    case APIC_LVTT:         /* LVT Timer Reg */
 
649
        vlapic->pt.irq = val & APIC_VECTOR_MASK;
 
650
    case APIC_LVTTHMR:      /* LVT Thermal Monitor */
 
651
    case APIC_LVTPC:        /* LVT Performance Counter */
 
652
    case APIC_LVT0:         /* LVT LINT0 Reg */
 
653
    case APIC_LVT1:         /* LVT Lint1 Reg */
 
654
    case APIC_LVTERR:       /* LVT Error Reg */
 
655
        if ( vlapic_sw_disabled(vlapic) )
 
656
            val |= APIC_LVT_MASKED;
 
657
        val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
 
658
        vlapic_set_reg(vlapic, offset, val);
 
659
        if ( offset == APIC_LVT0 )
 
660
        {
 
661
            vlapic_adjust_i8259_target(v->domain);
 
662
            pt_may_unmask_irq(v->domain, NULL);
 
663
        }
 
664
        if ( (offset == APIC_LVTT) && !(val & APIC_LVT_MASKED) )
 
665
            pt_may_unmask_irq(NULL, &vlapic->pt);
 
666
        break;
 
667
 
 
668
    case APIC_TMICT:
 
669
    {
 
670
        uint64_t period;
 
671
 
 
672
        vlapic_set_reg(vlapic, APIC_TMICT, val);
 
673
        if ( val == 0 )
 
674
        {
 
675
            destroy_periodic_time(&vlapic->pt);
 
676
            break;
 
677
        }
 
678
 
 
679
        period = ((uint64_t)APIC_BUS_CYCLE_NS *
 
680
                  (uint32_t)val * vlapic->hw.timer_divisor);
 
681
        create_periodic_time(current, &vlapic->pt, period, 
 
682
                             vlapic_lvtt_period(vlapic) ? period : 0,
 
683
                             vlapic->pt.irq, vlapic_pt_cb,
 
684
                             &vlapic->timer_last_update);
 
685
        vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
 
686
 
 
687
        HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
 
688
                    "bus cycle is %uns, "
 
689
                    "initial count %lu, period %"PRIu64"ns",
 
690
                    APIC_BUS_CYCLE_NS, val, period);
 
691
    }
 
692
    break;
 
693
 
 
694
    case APIC_TDCR:
 
695
        vlapic_set_tdcr(vlapic, val & 0xb);
 
696
        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
 
697
                    vlapic->hw.timer_divisor);
 
698
        break;
 
699
 
 
700
    default:
 
701
        gdprintk(XENLOG_DEBUG,
 
702
                 "Local APIC Write to read-only register 0x%x\n", offset);
 
703
        break;
 
704
    }
 
705
 
 
706
    return rc;
 
707
 
 
708
 unaligned_exit_and_crash:
 
709
    gdprintk(XENLOG_ERR, "Unaligned LAPIC write len=0x%lx at offset=0x%x.\n",
 
710
             len, offset);
 
711
 exit_and_crash:
 
712
    domain_crash(v->domain);
 
713
    return rc;
 
714
}
 
715
 
 
716
static int vlapic_range(struct vcpu *v, unsigned long addr)
 
717
{
 
718
    struct vlapic *vlapic = vcpu_vlapic(v);
 
719
    unsigned long offset  = addr - vlapic_base_address(vlapic);
 
720
    return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
 
721
}
 
722
 
 
723
const struct hvm_mmio_handler vlapic_mmio_handler = {
 
724
    .check_handler = vlapic_range,
 
725
    .read_handler = vlapic_read,
 
726
    .write_handler = vlapic_write
 
727
};
 
728
 
 
729
void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
 
730
{
 
731
    if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
 
732
    {
 
733
        if ( value & MSR_IA32_APICBASE_ENABLE )
 
734
        {
 
735
            vlapic_reset(vlapic);
 
736
            vlapic->hw.disabled &= ~VLAPIC_HW_DISABLED;
 
737
            pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
 
738
        }
 
739
        else
 
740
        {
 
741
            vlapic->hw.disabled |= VLAPIC_HW_DISABLED;
 
742
            pt_may_unmask_irq(vlapic_domain(vlapic), NULL);
 
743
        }
 
744
    }
 
745
 
 
746
    vlapic->hw.apic_base_msr = value;
 
747
 
 
748
    vmx_vlapic_msr_changed(vlapic_vcpu(vlapic));
 
749
 
 
750
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
 
751
                "apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr);
 
752
}
 
753
 
 
754
static int __vlapic_accept_pic_intr(struct vcpu *v)
 
755
{
 
756
    struct domain *d = v->domain;
 
757
    struct vlapic *vlapic = vcpu_vlapic(v);
 
758
    uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
 
759
    union vioapic_redir_entry redir0 = domain_vioapic(d)->redirtbl[0];
 
760
 
 
761
    /* We deliver 8259 interrupts to the appropriate CPU as follows. */
 
762
    return ((/* IOAPIC pin0 is unmasked and routing to this LAPIC? */
 
763
             ((redir0.fields.delivery_mode == dest_ExtINT) &&
 
764
              !redir0.fields.mask &&
 
765
              redir0.fields.dest_id == VLAPIC_ID(vlapic) &&
 
766
              !vlapic_disabled(vlapic)) ||
 
767
             /* LAPIC has LVT0 unmasked for ExtInts? */
 
768
             ((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
 
769
             /* LAPIC is fully disabled? */
 
770
             vlapic_hw_disabled(vlapic)));
 
771
}
 
772
 
 
773
int vlapic_accept_pic_intr(struct vcpu *v)
 
774
{
 
775
    return ((v == v->domain->arch.hvm_domain.i8259_target) &&
 
776
            __vlapic_accept_pic_intr(v));
 
777
}
 
778
 
 
779
void vlapic_adjust_i8259_target(struct domain *d)
 
780
{
 
781
    struct vcpu *v;
 
782
 
 
783
    for_each_vcpu ( d, v )
 
784
        if ( __vlapic_accept_pic_intr(v) )
 
785
            goto found;
 
786
 
 
787
    v = d->vcpu ? d->vcpu[0] : NULL;
 
788
 
 
789
 found:
 
790
    if ( d->arch.hvm_domain.i8259_target == v )
 
791
        return;
 
792
    d->arch.hvm_domain.i8259_target = v;
 
793
    pt_adjust_global_vcpu_target(v);
 
794
}
 
795
 
 
796
int vlapic_has_pending_irq(struct vcpu *v)
 
797
{
 
798
    struct vlapic *vlapic = vcpu_vlapic(v);
 
799
    int irr, isr;
 
800
 
 
801
    if ( !vlapic_enabled(vlapic) )
 
802
        return -1;
 
803
 
 
804
    irr = vlapic_find_highest_irr(vlapic);
 
805
    if ( irr == -1 )
 
806
        return -1;
 
807
 
 
808
    isr = vlapic_find_highest_isr(vlapic);
 
809
    isr = (isr != -1) ? isr : 0;
 
810
    if ( (isr & 0xf0) >= (irr & 0xf0) )
 
811
        return -1;
 
812
 
 
813
    return irr;
 
814
}
 
815
 
 
816
int vlapic_ack_pending_irq(struct vcpu *v, int vector)
 
817
{
 
818
    struct vlapic *vlapic = vcpu_vlapic(v);
 
819
 
 
820
    vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]);
 
821
    vlapic_clear_irr(vector, vlapic);
 
822
 
 
823
    return 1;
 
824
}
 
825
 
 
826
/* Reset the VLPAIC back to its power-on/reset state. */
 
827
void vlapic_reset(struct vlapic *vlapic)
 
828
{
 
829
    struct vcpu *v = vlapic_vcpu(vlapic);
 
830
    int i;
 
831
 
 
832
    vlapic_set_reg(vlapic, APIC_ID,  (v->vcpu_id * 2) << 24);
 
833
    vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
 
834
 
 
835
    for ( i = 0; i < 8; i++ )
 
836
    {
 
837
        vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
 
838
        vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
 
839
        vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
 
840
    }
 
841
    vlapic_set_reg(vlapic, APIC_ICR,     0);
 
842
    vlapic_set_reg(vlapic, APIC_ICR2,    0);
 
843
    vlapic_set_reg(vlapic, APIC_LDR,     0);
 
844
    vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
 
845
    vlapic_set_reg(vlapic, APIC_TMICT,   0);
 
846
    vlapic_set_reg(vlapic, APIC_TMCCT,   0);
 
847
    vlapic_set_tdcr(vlapic, 0);
 
848
 
 
849
    vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
 
850
 
 
851
    for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
 
852
        vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
 
853
 
 
854
    vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
 
855
    vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
 
856
 
 
857
    destroy_periodic_time(&vlapic->pt);
 
858
}
 
859
 
 
860
/* rearm the actimer if needed, after a HVM restore */
 
861
static void lapic_rearm(struct vlapic *s)
 
862
{
 
863
    unsigned long tmict = vlapic_get_reg(s, APIC_TMICT);
 
864
    uint64_t period;
 
865
 
 
866
    if ( (tmict = vlapic_get_reg(s, APIC_TMICT)) == 0 )
 
867
        return;
 
868
 
 
869
    period = ((uint64_t)APIC_BUS_CYCLE_NS *
 
870
              (uint32_t)tmict * s->hw.timer_divisor);
 
871
    s->pt.irq = vlapic_get_reg(s, APIC_LVTT) & APIC_VECTOR_MASK;
 
872
    create_periodic_time(vlapic_vcpu(s), &s->pt, period,
 
873
                         vlapic_lvtt_period(s) ? period : 0,
 
874
                         s->pt.irq, vlapic_pt_cb,
 
875
                         &s->timer_last_update);
 
876
    s->timer_last_update = s->pt.last_plt_gtime;
 
877
}
 
878
 
 
879
static int lapic_save_hidden(struct domain *d, hvm_domain_context_t *h)
 
880
{
 
881
    struct vcpu *v;
 
882
    struct vlapic *s;
 
883
    int rc = 0;
 
884
 
 
885
    for_each_vcpu ( d, v )
 
886
    {
 
887
        s = vcpu_vlapic(v);
 
888
        if ( (rc = hvm_save_entry(LAPIC, v->vcpu_id, h, &s->hw)) != 0 )
 
889
            break;
 
890
    }
 
891
 
 
892
    return rc;
 
893
}
 
894
 
 
895
static int lapic_save_regs(struct domain *d, hvm_domain_context_t *h)
 
896
{
 
897
    struct vcpu *v;
 
898
    struct vlapic *s;
 
899
    int rc = 0;
 
900
 
 
901
    for_each_vcpu ( d, v )
 
902
    {
 
903
        s = vcpu_vlapic(v);
 
904
        if ( (rc = hvm_save_entry(LAPIC_REGS, v->vcpu_id, h, s->regs)) != 0 )
 
905
            break;
 
906
    }
 
907
 
 
908
    return rc;
 
909
}
 
910
 
 
911
static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h)
 
912
{
 
913
    uint16_t vcpuid;
 
914
    struct vcpu *v;
 
915
    struct vlapic *s;
 
916
    
 
917
    /* Which vlapic to load? */
 
918
    vcpuid = hvm_load_instance(h); 
 
919
    if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
 
920
    {
 
921
        gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
 
922
        return -EINVAL;
 
923
    }
 
924
    s = vcpu_vlapic(v);
 
925
    
 
926
    if ( hvm_load_entry(LAPIC, h, &s->hw) != 0 ) 
 
927
        return -EINVAL;
 
928
 
 
929
    vmx_vlapic_msr_changed(v);
 
930
 
 
931
    return 0;
 
932
}
 
933
 
 
934
static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h)
 
935
{
 
936
    uint16_t vcpuid;
 
937
    struct vcpu *v;
 
938
    struct vlapic *s;
 
939
    
 
940
    /* Which vlapic to load? */
 
941
    vcpuid = hvm_load_instance(h); 
 
942
    if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
 
943
    {
 
944
        gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
 
945
        return -EINVAL;
 
946
    }
 
947
    s = vcpu_vlapic(v);
 
948
    
 
949
    if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 ) 
 
950
        return -EINVAL;
 
951
 
 
952
    vlapic_adjust_i8259_target(d);
 
953
    lapic_rearm(s);
 
954
    return 0;
 
955
}
 
956
 
 
957
HVM_REGISTER_SAVE_RESTORE(LAPIC, lapic_save_hidden, lapic_load_hidden,
 
958
                          1, HVMSR_PER_VCPU);
 
959
HVM_REGISTER_SAVE_RESTORE(LAPIC_REGS, lapic_save_regs, lapic_load_regs,
 
960
                          1, HVMSR_PER_VCPU);
 
961
 
 
962
int vlapic_init(struct vcpu *v)
 
963
{
 
964
    struct vlapic *vlapic = vcpu_vlapic(v);
 
965
    unsigned int memflags = MEMF_node(vcpu_to_node(v));
 
966
 
 
967
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "%d", v->vcpu_id);
 
968
 
 
969
    vlapic->pt.source = PTSRC_lapic;
 
970
 
 
971
#ifdef __i386__
 
972
    /* 32-bit VMX may be limited to 32-bit physical addresses. */
 
973
    if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
 
974
        memflags |= MEMF_bits(32);
 
975
#endif
 
976
    if (vlapic->regs_page == NULL)
 
977
    {
 
978
        vlapic->regs_page = alloc_domheap_page(NULL, memflags);
 
979
        if ( vlapic->regs_page == NULL )
 
980
        {
 
981
            dprintk(XENLOG_ERR, "alloc vlapic regs error: %d/%d\n",
 
982
                    v->domain->domain_id, v->vcpu_id);
 
983
            return -ENOMEM;
 
984
        }
 
985
    }
 
986
    if (vlapic->regs == NULL) 
 
987
    {
 
988
        vlapic->regs = __map_domain_page_global(vlapic->regs_page);
 
989
        if ( vlapic->regs == NULL )
 
990
        {
 
991
            dprintk(XENLOG_ERR, "map vlapic regs error: %d/%d\n",
 
992
                    v->domain->domain_id, v->vcpu_id);
 
993
            return -ENOMEM;
 
994
        }
 
995
    }
 
996
    clear_page(vlapic->regs);
 
997
 
 
998
    vlapic_reset(vlapic);
 
999
 
 
1000
    vlapic->hw.apic_base_msr = (MSR_IA32_APICBASE_ENABLE |
 
1001
                                APIC_DEFAULT_PHYS_BASE);
 
1002
    if ( v->vcpu_id == 0 )
 
1003
        vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP;
 
1004
 
 
1005
    tasklet_init(&vlapic->init_tasklet, vlapic_init_action, (unsigned long)v);
 
1006
 
 
1007
    return 0;
 
1008
}
 
1009
 
 
1010
void vlapic_destroy(struct vcpu *v)
 
1011
{
 
1012
    struct vlapic *vlapic = vcpu_vlapic(v);
 
1013
 
 
1014
    tasklet_kill(&vlapic->init_tasklet);
 
1015
    destroy_periodic_time(&vlapic->pt);
 
1016
    unmap_domain_page_global(vlapic->regs);
 
1017
    free_domheap_page(vlapic->regs_page);
 
1018
}