debuggers.hg

view xen/arch/x86/hvm/vlapic.c @ 22906:700ac6445812

Now add KDB to the non-kdb tree
author Mukesh Rathor
date Thu Feb 03 15:42:41 2011 -0800 (2011-02-03)
parents 4e108cf56d07
children
line source
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 */
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/apic.h>
35 #include <asm/io_apic.h>
36 #include <asm/hvm/hvm.h>
37 #include <asm/hvm/io.h>
38 #include <asm/hvm/support.h>
39 #include <asm/hvm/vmx/vmx.h>
40 #include <public/hvm/ioreq.h>
41 #include <public/hvm/params.h>
43 #define VLAPIC_VERSION 0x00050014
44 #define VLAPIC_LVT_NUM 6
46 /* vlapic's frequence is 100 MHz */
47 #define APIC_BUS_CYCLE_NS 10
49 #define LVT_MASK \
50 APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
52 #define LINT_MASK \
53 LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
54 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
56 static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
57 {
58 /* LVTT */
59 LVT_MASK | APIC_TIMER_MODE_MASK,
60 /* LVTTHMR */
61 LVT_MASK | APIC_MODE_MASK,
62 /* LVTPC */
63 LVT_MASK | APIC_MODE_MASK,
64 /* LVT0-1 */
65 LINT_MASK, LINT_MASK,
66 /* LVTERR */
67 LVT_MASK
68 };
70 /* Following could belong in apicdef.h */
71 #define APIC_SHORT_MASK 0xc0000
72 #define APIC_DEST_NOSHORT 0x0
73 #define APIC_DEST_MASK 0x800
75 #define vlapic_lvt_vector(vlapic, lvt_type) \
76 (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
78 #define vlapic_lvt_dm(vlapic, lvt_type) \
79 (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
81 #define vlapic_lvtt_period(vlapic) \
82 ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
83 == APIC_TIMER_MODE_PERIODIC)
85 #define vlapic_lvtt_oneshot(vlapic) \
86 ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
87 == APIC_TIMER_MODE_ONESHOT)
89 #define vlapic_lvtt_tdt(vlapic) \
90 ((vlapic_get_reg(vlapic, APIC_LVTT) & APIC_TIMER_MODE_MASK) \
91 == APIC_TIMER_MODE_TSC_DEADLINE)
94 /*
95 * Generic APIC bitmap vector update & search routines.
96 */
98 #define VEC_POS(v) ((v)%32)
99 #define REG_POS(v) (((v)/32) * 0x10)
100 #define vlapic_test_and_set_vector(vec, bitmap) \
101 test_and_set_bit(VEC_POS(vec), \
102 (unsigned long *)((bitmap) + REG_POS(vec)))
103 #define vlapic_test_and_clear_vector(vec, bitmap) \
104 test_and_clear_bit(VEC_POS(vec), \
105 (unsigned long *)((bitmap) + REG_POS(vec)))
106 #define vlapic_set_vector(vec, bitmap) \
107 set_bit(VEC_POS(vec), (unsigned long *)((bitmap) + REG_POS(vec)))
108 #define vlapic_clear_vector(vec, bitmap) \
109 clear_bit(VEC_POS(vec), (unsigned long *)((bitmap) + REG_POS(vec)))
111 static int vlapic_find_highest_vector(void *bitmap)
112 {
113 uint32_t *word = bitmap;
114 int word_offset = MAX_VECTOR / 32;
116 /* Work backwards through the bitmap (first 32-bit word in every four). */
117 while ( (word_offset != 0) && (word[(--word_offset)*4] == 0) )
118 continue;
120 return (fls(word[word_offset*4]) - 1) + (word_offset * 32);
121 }
124 /*
125 * IRR-specific bitmap update & search routines.
126 */
128 static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
129 {
130 return vlapic_test_and_set_vector(vector, &vlapic->regs->data[APIC_IRR]);
131 }
133 static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
134 {
135 vlapic_clear_vector(vector, &vlapic->regs->data[APIC_IRR]);
136 }
138 static int vlapic_find_highest_irr(struct vlapic *vlapic)
139 {
140 return vlapic_find_highest_vector(&vlapic->regs->data[APIC_IRR]);
141 }
143 int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
144 {
145 int ret;
147 ret = !vlapic_test_and_set_irr(vec, vlapic);
148 if ( trig )
149 vlapic_set_vector(vec, &vlapic->regs->data[APIC_TMR]);
151 /* We may need to wake up target vcpu, besides set pending bit here */
152 return ret;
153 }
155 static int vlapic_find_highest_isr(struct vlapic *vlapic)
156 {
157 return vlapic_find_highest_vector(&vlapic->regs->data[APIC_ISR]);
158 }
160 static uint32_t vlapic_get_ppr(struct vlapic *vlapic)
161 {
162 uint32_t tpr, isrv, ppr;
163 int isr;
165 tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
166 isr = vlapic_find_highest_isr(vlapic);
167 isrv = (isr != -1) ? isr : 0;
169 if ( (tpr & 0xf0) >= (isrv & 0xf0) )
170 ppr = tpr & 0xff;
171 else
172 ppr = isrv & 0xf0;
174 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
175 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
176 vlapic, ppr, isr, isrv);
178 return ppr;
179 }
181 static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda)
182 {
183 int result = 0;
184 uint32_t logical_id;
186 if ( vlapic_x2apic_mode(vlapic) )
187 {
188 logical_id = vlapic_get_reg(vlapic, APIC_LDR);
189 return !!(logical_id & mda);
190 }
192 logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR));
194 switch ( vlapic_get_reg(vlapic, APIC_DFR) )
195 {
196 case APIC_DFR_FLAT:
197 if ( logical_id & mda )
198 result = 1;
199 break;
200 case APIC_DFR_CLUSTER:
201 if ( ((logical_id >> 4) == (mda >> 0x4)) && (logical_id & mda & 0xf) )
202 result = 1;
203 break;
204 default:
205 gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d: %08x\n",
206 vlapic_vcpu(vlapic)->vcpu_id,
207 vlapic_get_reg(vlapic, APIC_DFR));
208 break;
209 }
211 return result;
212 }
214 bool_t vlapic_match_dest(
215 struct vlapic *target, struct vlapic *source,
216 int short_hand, uint8_t dest, uint8_t dest_mode)
217 {
218 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
219 "dest_mode 0x%x, short_hand 0x%x",
220 target, source, dest, dest_mode, short_hand);
222 switch ( short_hand )
223 {
224 case APIC_DEST_NOSHORT:
225 if ( dest_mode )
226 return vlapic_match_logical_addr(target, dest);
227 return ((dest == 0xFF) || (dest == VLAPIC_ID(target)));
229 case APIC_DEST_SELF:
230 return (target == source);
232 case APIC_DEST_ALLINC:
233 return 1;
235 case APIC_DEST_ALLBUT:
236 return (target != source);
238 default:
239 gdprintk(XENLOG_WARNING, "Bad dest shorthand value %x\n", short_hand);
240 break;
241 }
243 return 0;
244 }
246 static void vlapic_init_sipi_action(unsigned long _vcpu)
247 {
248 struct vcpu *origin = (struct vcpu *)_vcpu;
249 struct vcpu *target = vcpu_vlapic(origin)->init_sipi.target;
250 uint32_t icr = vcpu_vlapic(origin)->init_sipi.icr;
252 vcpu_pause(target);
254 switch ( icr & APIC_MODE_MASK )
255 {
256 case APIC_DM_INIT: {
257 bool_t fpu_initialised;
258 domain_lock(target->domain);
259 /* Reset necessary VCPU state. This does not include FPU state. */
260 fpu_initialised = target->fpu_initialised;
261 vcpu_reset(target);
262 target->fpu_initialised = fpu_initialised;
263 vlapic_reset(vcpu_vlapic(target));
264 domain_unlock(target->domain);
265 break;
266 }
268 case APIC_DM_STARTUP: {
269 uint16_t reset_cs = (icr & 0xffu) << 8;
270 hvm_vcpu_reset_state(target, reset_cs, 0);
271 break;
272 }
274 default:
275 BUG();
276 }
278 vcpu_unpause(target);
280 vcpu_vlapic(origin)->init_sipi.target = NULL;
281 vcpu_unpause(origin);
282 }
284 static int vlapic_schedule_init_sipi_tasklet(struct vcpu *target, uint32_t icr)
285 {
286 struct vcpu *origin = current;
288 if ( vcpu_vlapic(origin)->init_sipi.target != NULL )
289 {
290 WARN(); /* should be impossible but don't BUG, just in case */
291 return X86EMUL_UNHANDLEABLE;
292 }
294 vcpu_pause_nosync(origin);
296 vcpu_vlapic(origin)->init_sipi.target = target;
297 vcpu_vlapic(origin)->init_sipi.icr = icr;
298 tasklet_schedule(&vcpu_vlapic(origin)->init_sipi.tasklet);
300 return X86EMUL_RETRY;
301 }
303 /* Add a pending IRQ into lapic. */
304 static int vlapic_accept_irq(struct vcpu *v, uint32_t icr_low)
305 {
306 struct vlapic *vlapic = vcpu_vlapic(v);
307 uint8_t vector = (uint8_t)icr_low;
308 int rc = X86EMUL_OKAY;
310 switch ( icr_low & APIC_MODE_MASK )
311 {
312 case APIC_DM_FIXED:
313 case APIC_DM_LOWEST:
314 if ( vlapic_enabled(vlapic) &&
315 !vlapic_test_and_set_irr(vector, vlapic) )
316 vcpu_kick(v);
317 break;
319 case APIC_DM_REMRD:
320 gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3\n");
321 break;
323 case APIC_DM_SMI:
324 gdprintk(XENLOG_WARNING, "Ignoring guest SMI\n");
325 break;
327 case APIC_DM_NMI:
328 if ( !test_and_set_bool(v->nmi_pending) )
329 vcpu_kick(v);
330 break;
332 case APIC_DM_INIT:
333 /* No work on INIT de-assert for P4-type APIC. */
334 if ( (icr_low & (APIC_INT_LEVELTRIG | APIC_INT_ASSERT)) ==
335 APIC_INT_LEVELTRIG )
336 break;
337 /* Nothing to do if the VCPU is already reset. */
338 if ( !v->is_initialised )
339 break;
340 hvm_vcpu_down(v);
341 rc = vlapic_schedule_init_sipi_tasklet(v, icr_low);
342 break;
344 case APIC_DM_STARTUP:
345 /* Nothing to do if the VCPU is already initialised. */
346 if ( v->is_initialised )
347 break;
348 rc = vlapic_schedule_init_sipi_tasklet(v, icr_low);
349 break;
351 default:
352 gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode in ICR %x\n",
353 icr_low);
354 domain_crash(v->domain);
355 }
357 return rc;
358 }
360 struct vlapic *vlapic_lowest_prio(
361 struct domain *d, struct vlapic *source,
362 int short_hand, uint8_t dest, uint8_t dest_mode)
363 {
364 int old = d->arch.hvm_domain.irq.round_robin_prev_vcpu;
365 uint32_t ppr, target_ppr = UINT_MAX;
366 struct vlapic *vlapic, *target = NULL;
367 struct vcpu *v;
369 if ( unlikely(!d->vcpu) || unlikely((v = d->vcpu[old]) == NULL) )
370 return NULL;
372 do {
373 v = v->next_in_list ? : d->vcpu[0];
374 vlapic = vcpu_vlapic(v);
375 if ( vlapic_match_dest(vlapic, source, short_hand, dest, dest_mode) &&
376 vlapic_enabled(vlapic) &&
377 ((ppr = vlapic_get_ppr(vlapic)) < target_ppr) )
378 {
379 target = vlapic;
380 target_ppr = ppr;
381 }
382 } while ( v->vcpu_id != old );
384 if ( target != NULL )
385 d->arch.hvm_domain.irq.round_robin_prev_vcpu =
386 vlapic_vcpu(target)->vcpu_id;
388 return target;
389 }
391 void vlapic_EOI_set(struct vlapic *vlapic)
392 {
393 int vector = vlapic_find_highest_isr(vlapic);
395 /* Some EOI writes may not have a matching to an in-service interrupt. */
396 if ( vector == -1 )
397 return;
399 vlapic_clear_vector(vector, &vlapic->regs->data[APIC_ISR]);
401 if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
402 vioapic_update_EOI(vlapic_domain(vlapic), vector);
404 hvm_dpci_msi_eoi(current->domain, vector);
405 }
407 int vlapic_ipi(
408 struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
409 {
410 unsigned int dest;
411 unsigned int short_hand = icr_low & APIC_SHORT_MASK;
412 unsigned int dest_mode = !!(icr_low & APIC_DEST_MASK);
413 struct vlapic *target;
414 struct vcpu *v;
415 int rc = X86EMUL_OKAY;
417 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low);
419 dest = (vlapic_x2apic_mode(vlapic)
420 ? icr_high
421 : GET_xAPIC_DEST_FIELD(icr_high));
423 if ( (icr_low & APIC_MODE_MASK) == APIC_DM_LOWEST )
424 {
425 target = vlapic_lowest_prio(vlapic_domain(vlapic), vlapic,
426 short_hand, dest, dest_mode);
427 if ( target != NULL )
428 rc = vlapic_accept_irq(vlapic_vcpu(target), icr_low);
429 return rc;
430 }
432 for_each_vcpu ( vlapic_domain(vlapic), v )
433 {
434 if ( vlapic_match_dest(vcpu_vlapic(v), vlapic,
435 short_hand, dest, dest_mode) )
436 rc = vlapic_accept_irq(v, icr_low);
437 if ( rc != X86EMUL_OKAY )
438 break;
439 }
441 return rc;
442 }
444 static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
445 {
446 struct vcpu *v = current;
447 uint32_t tmcct = 0, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
448 uint64_t counter_passed;
450 counter_passed = ((hvm_get_guest_time(v) - vlapic->timer_last_update)
451 / (APIC_BUS_CYCLE_NS * vlapic->hw.timer_divisor));
453 if ( tmict != 0 )
454 {
455 if ( vlapic_lvtt_period(vlapic) )
456 counter_passed %= tmict;
457 if ( counter_passed < tmict )
458 tmcct = tmict - counter_passed;
459 }
461 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
462 "timer initial count %d, timer current count %d, "
463 "offset %"PRId64,
464 tmict, tmcct, counter_passed);
466 return tmcct;
467 }
469 static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
470 {
471 /* Only bits 0, 1 and 3 are settable; others are MBZ. */
472 val &= 0xb;
473 vlapic_set_reg(vlapic, APIC_TDCR, val);
475 /* Update the demangled hw.timer_divisor. */
476 val = ((val & 3) | ((val & 8) >> 1)) + 1;
477 vlapic->hw.timer_divisor = 1 << (val & 7);
479 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
480 "timer_divisor: %d", vlapic->hw.timer_divisor);
481 }
483 static void vlapic_read_aligned(
484 struct vlapic *vlapic, unsigned int offset, unsigned int *result)
485 {
486 switch ( offset )
487 {
488 case APIC_PROCPRI:
489 *result = vlapic_get_ppr(vlapic);
490 break;
492 case APIC_TMCCT: /* Timer CCR */
493 if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
494 {
495 *result = 0;
496 break;
497 }
498 *result = vlapic_get_tmcct(vlapic);
499 break;
501 case APIC_TMICT: /* Timer ICR */
502 if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
503 {
504 *result = 0;
505 break;
506 }
507 default:
508 *result = vlapic_get_reg(vlapic, offset);
509 break;
510 }
511 }
513 static int vlapic_read(
514 struct vcpu *v, unsigned long address,
515 unsigned long len, unsigned long *pval)
516 {
517 unsigned int alignment;
518 unsigned int tmp;
519 unsigned long result = 0;
520 struct vlapic *vlapic = vcpu_vlapic(v);
521 unsigned int offset = address - vlapic_base_address(vlapic);
523 if ( offset > (APIC_TDCR + 0x3) )
524 goto out;
526 alignment = offset & 0x3;
528 vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
529 switch ( len )
530 {
531 case 1:
532 result = *((unsigned char *)&tmp + alignment);
533 break;
535 case 2:
536 if ( alignment == 3 )
537 goto unaligned_exit_and_crash;
538 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
539 break;
541 case 4:
542 if ( alignment != 0 )
543 goto unaligned_exit_and_crash;
544 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
545 break;
547 default:
548 gdprintk(XENLOG_ERR, "Local APIC read with len=0x%lx, "
549 "should be 4 instead.\n", len);
550 goto exit_and_crash;
551 }
553 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
554 "and the result is 0x%lx", offset, len, result);
556 out:
557 *pval = result;
558 return X86EMUL_OKAY;
560 unaligned_exit_and_crash:
561 gdprintk(XENLOG_ERR, "Unaligned LAPIC read len=0x%lx at offset=0x%x.\n",
562 len, offset);
563 exit_and_crash:
564 domain_crash(v->domain);
565 return X86EMUL_OKAY;
566 }
568 int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content)
569 {
570 struct vlapic *vlapic = vcpu_vlapic(v);
571 uint32_t low, high = 0, offset = (msr - MSR_IA32_APICBASE_MSR) << 4;
573 if ( !vlapic_x2apic_mode(vlapic) )
574 return 1;
576 vlapic_read_aligned(vlapic, offset, &low);
577 if ( offset == APIC_ICR )
578 vlapic_read_aligned(vlapic, APIC_ICR2, &high);
580 *msr_content = (((uint64_t)high) << 32) | low;
581 return 0;
582 }
584 static void vlapic_pt_cb(struct vcpu *v, void *data)
585 {
586 *(s_time_t *)data = hvm_get_guest_time(v);
587 }
589 static void vlapic_tdt_pt_cb(struct vcpu *v, void *data)
590 {
591 *(s_time_t *)data = hvm_get_guest_time(v);
592 vcpu_vlapic(v)->hw.tdt_msr = 0;
593 }
595 static int vlapic_reg_write(struct vcpu *v,
596 unsigned int offset, unsigned long val)
597 {
598 struct vlapic *vlapic = vcpu_vlapic(v);
599 int rc = X86EMUL_OKAY;
601 switch ( offset )
602 {
603 case APIC_ID:
604 if ( !vlapic_x2apic_mode(vlapic) )
605 vlapic_set_reg(vlapic, APIC_ID, val);
606 else
607 rc = X86EMUL_UNHANDLEABLE;
608 break;
610 case APIC_TASKPRI:
611 vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
612 break;
614 case APIC_EOI:
615 vlapic_EOI_set(vlapic);
616 break;
618 case APIC_LDR:
619 if ( !vlapic_x2apic_mode(vlapic) )
620 vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
621 else
622 rc = X86EMUL_UNHANDLEABLE;
623 break;
625 case APIC_DFR:
626 if ( !vlapic_x2apic_mode(vlapic) )
627 vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
628 else
629 rc = X86EMUL_UNHANDLEABLE;
630 break;
632 case APIC_SPIV:
633 vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
635 if ( !(val & APIC_SPIV_APIC_ENABLED) )
636 {
637 int i;
638 uint32_t lvt_val;
640 vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
642 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
643 {
644 lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
645 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
646 lvt_val | APIC_LVT_MASKED);
647 }
648 }
649 else
650 {
651 vlapic->hw.disabled &= ~VLAPIC_SW_DISABLED;
652 pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
653 }
654 break;
656 case APIC_ESR:
657 if ( vlapic_x2apic_mode(vlapic) && (val != 0) )
658 {
659 gdprintk(XENLOG_ERR, "Local APIC write ESR with non-zero %lx\n",
660 val);
661 rc = X86EMUL_UNHANDLEABLE;
662 }
663 break;
665 case APIC_SELF_IPI:
666 if ( vlapic_x2apic_mode(vlapic) )
667 vlapic_reg_write(v, APIC_ICR, 0x40000 | (val & 0xff));
668 else
669 rc = X86EMUL_UNHANDLEABLE;
670 break;
672 case APIC_ICR:
673 val &= ~(1 << 12); /* always clear the pending bit */
674 rc = vlapic_ipi(vlapic, val, vlapic_get_reg(vlapic, APIC_ICR2));
675 if ( rc == X86EMUL_OKAY )
676 vlapic_set_reg(vlapic, APIC_ICR, val);
677 break;
679 case APIC_ICR2:
680 if ( !vlapic_x2apic_mode(vlapic) )
681 val &= 0xff000000;
682 vlapic_set_reg(vlapic, APIC_ICR2, val);
683 break;
685 case APIC_LVTT: /* LVT Timer Reg */
686 if ( (vlapic_get_reg(vlapic, offset) & APIC_TIMER_MODE_MASK) !=
687 (val & APIC_TIMER_MODE_MASK) )
688 {
689 destroy_periodic_time(&vlapic->pt);
690 vlapic_set_reg(vlapic, APIC_TMICT, 0);
691 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
692 vlapic->hw.tdt_msr = 0;
693 }
694 vlapic->pt.irq = val & APIC_VECTOR_MASK;
695 case APIC_LVTTHMR: /* LVT Thermal Monitor */
696 case APIC_LVTPC: /* LVT Performance Counter */
697 case APIC_LVT0: /* LVT LINT0 Reg */
698 case APIC_LVT1: /* LVT Lint1 Reg */
699 case APIC_LVTERR: /* LVT Error Reg */
700 if ( vlapic_sw_disabled(vlapic) )
701 val |= APIC_LVT_MASKED;
702 val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
703 vlapic_set_reg(vlapic, offset, val);
704 if ( offset == APIC_LVT0 )
705 {
706 vlapic_adjust_i8259_target(v->domain);
707 pt_may_unmask_irq(v->domain, NULL);
708 }
709 if ( (offset == APIC_LVTT) && !(val & APIC_LVT_MASKED) )
710 pt_may_unmask_irq(NULL, &vlapic->pt);
711 break;
713 case APIC_TMICT:
714 {
715 uint64_t period;
717 if ( !vlapic_lvtt_oneshot(vlapic) && !vlapic_lvtt_period(vlapic) )
718 break;
720 vlapic_set_reg(vlapic, APIC_TMICT, val);
721 if ( val == 0 )
722 {
723 destroy_periodic_time(&vlapic->pt);
724 break;
725 }
727 period = ((uint64_t)APIC_BUS_CYCLE_NS *
728 (uint32_t)val * vlapic->hw.timer_divisor);
729 create_periodic_time(current, &vlapic->pt, period,
730 vlapic_lvtt_period(vlapic) ? period : 0,
731 vlapic->pt.irq,
732 vlapic_lvtt_period(vlapic) ? vlapic_pt_cb : NULL,
733 &vlapic->timer_last_update);
734 vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
736 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
737 "bus cycle is %uns, "
738 "initial count %lu, period %"PRIu64"ns",
739 APIC_BUS_CYCLE_NS, val, period);
740 }
741 break;
743 case APIC_TDCR:
744 vlapic_set_tdcr(vlapic, val & 0xb);
745 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
746 vlapic->hw.timer_divisor);
747 break;
749 default:
750 break;
751 }
752 if (rc == X86EMUL_UNHANDLEABLE)
753 gdprintk(XENLOG_DEBUG,
754 "Local APIC Write wrong to register 0x%x\n", offset);
755 return rc;
756 }
758 static int vlapic_write(struct vcpu *v, unsigned long address,
759 unsigned long len, unsigned long val)
760 {
761 struct vlapic *vlapic = vcpu_vlapic(v);
762 unsigned int offset = address - vlapic_base_address(vlapic);
763 int rc = X86EMUL_OKAY;
765 if ( offset != 0xb0 )
766 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
767 "offset 0x%x with length 0x%lx, and value is 0x%lx",
768 offset, len, val);
770 /*
771 * According to the IA32 Manual, all accesses should be 32 bits.
772 * Some OSes do 8- or 16-byte accesses, however.
773 */
774 val = (uint32_t)val;
775 if ( len != 4 )
776 {
777 unsigned int tmp;
778 unsigned char alignment;
780 gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
782 alignment = offset & 0x3;
783 (void)vlapic_read_aligned(vlapic, offset & ~0x3, &tmp);
785 switch ( len )
786 {
787 case 1:
788 val = ((tmp & ~(0xff << (8*alignment))) |
789 ((val & 0xff) << (8*alignment)));
790 break;
792 case 2:
793 if ( alignment & 1 )
794 goto unaligned_exit_and_crash;
795 val = ((tmp & ~(0xffff << (8*alignment))) |
796 ((val & 0xffff) << (8*alignment)));
797 break;
799 default:
800 gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
801 "should be 4 instead\n", len);
802 goto exit_and_crash;
803 }
804 }
805 else if ( (offset & 0x3) != 0 )
806 goto unaligned_exit_and_crash;
808 offset &= ~0x3;
810 return vlapic_reg_write(v, offset, val);
812 unaligned_exit_and_crash:
813 gdprintk(XENLOG_ERR, "Unaligned LAPIC write len=0x%lx at offset=0x%x.\n",
814 len, offset);
815 exit_and_crash:
816 domain_crash(v->domain);
817 return rc;
818 }
820 int hvm_x2apic_msr_write(struct vcpu *v, unsigned int msr, uint64_t msr_content)
821 {
822 struct vlapic *vlapic = vcpu_vlapic(v);
823 uint32_t offset = (msr - MSR_IA32_APICBASE_MSR) << 4;
824 int rc;
826 if ( !vlapic_x2apic_mode(vlapic) )
827 return 1;
829 if ( offset == APIC_ICR )
830 if ( vlapic_reg_write(v, APIC_ICR2 , (uint32_t)(msr_content >> 32)) )
831 return 1;
833 rc = vlapic_reg_write(v, offset, (uint32_t)msr_content);
835 /* X86EMUL_RETRY for SIPI */
836 return ((rc != X86EMUL_OKAY) && (rc != X86EMUL_RETRY));
837 }
839 static int vlapic_range(struct vcpu *v, unsigned long addr)
840 {
841 struct vlapic *vlapic = vcpu_vlapic(v);
842 unsigned long offset = addr - vlapic_base_address(vlapic);
843 return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
844 }
846 const struct hvm_mmio_handler vlapic_mmio_handler = {
847 .check_handler = vlapic_range,
848 .read_handler = vlapic_read,
849 .write_handler = vlapic_write
850 };
852 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
853 {
854 if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
855 {
856 if ( value & MSR_IA32_APICBASE_ENABLE )
857 {
858 vlapic_reset(vlapic);
859 vlapic->hw.disabled &= ~VLAPIC_HW_DISABLED;
860 pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
861 }
862 else
863 {
864 vlapic->hw.disabled |= VLAPIC_HW_DISABLED;
865 pt_may_unmask_irq(vlapic_domain(vlapic), NULL);
866 }
867 }
869 vlapic->hw.apic_base_msr = value;
871 if ( vlapic_x2apic_mode(vlapic) )
872 {
873 u32 id = vlapic_get_reg(vlapic, APIC_ID);
874 u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf));
875 vlapic_set_reg(vlapic, APIC_LDR, ldr);
876 }
878 vmx_vlapic_msr_changed(vlapic_vcpu(vlapic));
880 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
881 "apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr);
882 }
884 uint64_t vlapic_tdt_msr_get(struct vlapic *vlapic)
885 {
886 if ( !vlapic_lvtt_tdt(vlapic) )
887 return 0;
889 return vlapic->hw.tdt_msr;
890 }
892 void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value)
893 {
894 uint64_t guest_tsc;
895 uint64_t guest_time;
896 struct vcpu *v = vlapic_vcpu(vlapic);
898 /* may need to exclude some other conditions like vlapic->hw.disabled */
899 if ( !vlapic_lvtt_tdt(vlapic) )
900 {
901 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "ignore tsc deadline msr write");
902 return;
903 }
905 /* new_value = 0, >0 && <= now, > now */
906 guest_tsc = hvm_get_guest_tsc(v);
907 guest_time = hvm_get_guest_time(v);
908 if ( value > guest_tsc )
909 {
910 uint64_t delta = value - v->arch.hvm_vcpu.cache_tsc_offset;
911 delta = gtsc_to_gtime(v->domain, delta);
912 delta = max_t(s64, delta - guest_time, 0);
914 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "delta[0x%016"PRIx64"]", delta);
916 vlapic->hw.tdt_msr = value;
917 /* .... reprogram tdt timer */
918 create_periodic_time(v, &vlapic->pt, delta, 0,
919 vlapic->pt.irq, vlapic_tdt_pt_cb,
920 &vlapic->timer_last_update);
921 vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
922 }
923 else
924 {
925 vlapic->hw.tdt_msr = 0;
927 /* trigger a timer event if needed */
928 if ( value > 0 )
929 {
930 create_periodic_time(v, &vlapic->pt, 0, 0,
931 vlapic->pt.irq, vlapic_tdt_pt_cb,
932 &vlapic->timer_last_update);
933 vlapic->timer_last_update = vlapic->pt.last_plt_gtime;
934 }
935 else
936 {
937 /* .... stop tdt timer */
938 destroy_periodic_time(&vlapic->pt);
939 }
941 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "value[0x%016"PRIx64"]", value);
942 }
944 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
945 "tdt_msr[0x%016"PRIx64"],"
946 " gtsc[0x%016"PRIx64"],"
947 " gtime[0x%016"PRIx64"]",
948 vlapic->hw.tdt_msr, guest_tsc, guest_time);
949 }
951 static int __vlapic_accept_pic_intr(struct vcpu *v)
952 {
953 struct domain *d = v->domain;
954 struct vlapic *vlapic = vcpu_vlapic(v);
955 uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
956 union vioapic_redir_entry redir0 = domain_vioapic(d)->redirtbl[0];
958 /* We deliver 8259 interrupts to the appropriate CPU as follows. */
959 return ((/* IOAPIC pin0 is unmasked and routing to this LAPIC? */
960 ((redir0.fields.delivery_mode == dest_ExtINT) &&
961 !redir0.fields.mask &&
962 redir0.fields.dest_id == VLAPIC_ID(vlapic) &&
963 !vlapic_disabled(vlapic)) ||
964 /* LAPIC has LVT0 unmasked for ExtInts? */
965 ((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
966 /* LAPIC is fully disabled? */
967 vlapic_hw_disabled(vlapic)));
968 }
970 int vlapic_accept_pic_intr(struct vcpu *v)
971 {
972 return ((v == v->domain->arch.hvm_domain.i8259_target) &&
973 __vlapic_accept_pic_intr(v));
974 }
976 void vlapic_adjust_i8259_target(struct domain *d)
977 {
978 struct vcpu *v;
980 for_each_vcpu ( d, v )
981 if ( __vlapic_accept_pic_intr(v) )
982 goto found;
984 v = d->vcpu ? d->vcpu[0] : NULL;
986 found:
987 if ( d->arch.hvm_domain.i8259_target == v )
988 return;
989 d->arch.hvm_domain.i8259_target = v;
990 pt_adjust_global_vcpu_target(v);
991 }
993 int vlapic_has_pending_irq(struct vcpu *v)
994 {
995 struct vlapic *vlapic = vcpu_vlapic(v);
996 int irr, isr;
998 if ( !vlapic_enabled(vlapic) )
999 return -1;
1001 irr = vlapic_find_highest_irr(vlapic);
1002 if ( irr == -1 )
1003 return -1;
1005 isr = vlapic_find_highest_isr(vlapic);
1006 isr = (isr != -1) ? isr : 0;
1007 if ( (isr & 0xf0) >= (irr & 0xf0) )
1008 return -1;
1010 return irr;
1013 int vlapic_ack_pending_irq(struct vcpu *v, int vector)
1015 struct vlapic *vlapic = vcpu_vlapic(v);
1017 vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]);
1018 vlapic_clear_irr(vector, vlapic);
1020 return 1;
1023 bool_t is_vlapic_lvtpc_enabled(struct vlapic *vlapic)
1025 return (vlapic_enabled(vlapic) &&
1026 !(vlapic_get_reg(vlapic, APIC_LVTPC) & APIC_LVT_MASKED));
1029 /* Reset the VLPAIC back to its power-on/reset state. */
1030 void vlapic_reset(struct vlapic *vlapic)
1032 struct vcpu *v = vlapic_vcpu(vlapic);
1033 int i;
1035 vlapic_set_reg(vlapic, APIC_ID, (v->vcpu_id * 2) << 24);
1036 vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
1038 for ( i = 0; i < 8; i++ )
1040 vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
1041 vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
1042 vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
1044 vlapic_set_reg(vlapic, APIC_ICR, 0);
1045 vlapic_set_reg(vlapic, APIC_ICR2, 0);
1046 vlapic_set_reg(vlapic, APIC_LDR, 0);
1047 vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
1048 vlapic_set_reg(vlapic, APIC_TMICT, 0);
1049 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
1050 vlapic_set_tdcr(vlapic, 0);
1052 vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
1054 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
1055 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
1057 vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
1058 vlapic->hw.disabled |= VLAPIC_SW_DISABLED;
1060 destroy_periodic_time(&vlapic->pt);
1063 /* rearm the actimer if needed, after a HVM restore */
1064 static void lapic_rearm(struct vlapic *s)
1066 unsigned long tmict;
1067 uint64_t period, tdt_msr;
1069 s->pt.irq = vlapic_get_reg(s, APIC_LVTT) & APIC_VECTOR_MASK;
1071 if ( vlapic_lvtt_tdt(s) )
1073 if ( (tdt_msr = vlapic_tdt_msr_get(s)) != 0 )
1074 vlapic_tdt_msr_set(s, tdt_msr);
1075 return;
1078 if ( (tmict = vlapic_get_reg(s, APIC_TMICT)) == 0 )
1079 return;
1081 period = ((uint64_t)APIC_BUS_CYCLE_NS *
1082 (uint32_t)tmict * s->hw.timer_divisor);
1083 create_periodic_time(vlapic_vcpu(s), &s->pt, period,
1084 vlapic_lvtt_period(s) ? period : 0,
1085 s->pt.irq,
1086 vlapic_lvtt_period(s) ? vlapic_pt_cb : NULL,
1087 &s->timer_last_update);
1088 s->timer_last_update = s->pt.last_plt_gtime;
1091 static int lapic_save_hidden(struct domain *d, hvm_domain_context_t *h)
1093 struct vcpu *v;
1094 struct vlapic *s;
1095 int rc = 0;
1097 for_each_vcpu ( d, v )
1099 s = vcpu_vlapic(v);
1100 if ( (rc = hvm_save_entry(LAPIC, v->vcpu_id, h, &s->hw)) != 0 )
1101 break;
1104 return rc;
1107 static int lapic_save_regs(struct domain *d, hvm_domain_context_t *h)
1109 struct vcpu *v;
1110 struct vlapic *s;
1111 int rc = 0;
1113 for_each_vcpu ( d, v )
1115 s = vcpu_vlapic(v);
1116 if ( (rc = hvm_save_entry(LAPIC_REGS, v->vcpu_id, h, s->regs)) != 0 )
1117 break;
1120 return rc;
1123 static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h)
1125 uint16_t vcpuid;
1126 struct vcpu *v;
1127 struct vlapic *s;
1129 /* Which vlapic to load? */
1130 vcpuid = hvm_load_instance(h);
1131 if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
1133 gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
1134 return -EINVAL;
1136 s = vcpu_vlapic(v);
1138 if ( hvm_load_entry_zeroextend(LAPIC, h, &s->hw) != 0 )
1139 return -EINVAL;
1141 vmx_vlapic_msr_changed(v);
1143 return 0;
1146 static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h)
1148 uint16_t vcpuid;
1149 struct vcpu *v;
1150 struct vlapic *s;
1152 /* Which vlapic to load? */
1153 vcpuid = hvm_load_instance(h);
1154 if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
1156 gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
1157 return -EINVAL;
1159 s = vcpu_vlapic(v);
1161 if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 )
1162 return -EINVAL;
1164 vlapic_adjust_i8259_target(d);
1165 lapic_rearm(s);
1166 return 0;
1169 HVM_REGISTER_SAVE_RESTORE(LAPIC, lapic_save_hidden, lapic_load_hidden,
1170 1, HVMSR_PER_VCPU);
1171 HVM_REGISTER_SAVE_RESTORE(LAPIC_REGS, lapic_save_regs, lapic_load_regs,
1172 1, HVMSR_PER_VCPU);
1174 int vlapic_init(struct vcpu *v)
1176 struct vlapic *vlapic = vcpu_vlapic(v);
1177 unsigned int memflags = MEMF_node(vcpu_to_node(v));
1179 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "%d", v->vcpu_id);
1181 vlapic->pt.source = PTSRC_lapic;
1183 #ifdef __i386__
1184 /* 32-bit VMX may be limited to 32-bit physical addresses. */
1185 if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
1186 memflags |= MEMF_bits(32);
1187 #endif
1188 if (vlapic->regs_page == NULL)
1190 vlapic->regs_page = alloc_domheap_page(NULL, memflags);
1191 if ( vlapic->regs_page == NULL )
1193 dprintk(XENLOG_ERR, "alloc vlapic regs error: %d/%d\n",
1194 v->domain->domain_id, v->vcpu_id);
1195 return -ENOMEM;
1198 if (vlapic->regs == NULL)
1200 vlapic->regs = __map_domain_page_global(vlapic->regs_page);
1201 if ( vlapic->regs == NULL )
1203 dprintk(XENLOG_ERR, "map vlapic regs error: %d/%d\n",
1204 v->domain->domain_id, v->vcpu_id);
1205 return -ENOMEM;
1208 clear_page(vlapic->regs);
1210 vlapic_reset(vlapic);
1212 vlapic->hw.apic_base_msr = (MSR_IA32_APICBASE_ENABLE |
1213 APIC_DEFAULT_PHYS_BASE);
1214 if ( v->vcpu_id == 0 )
1215 vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP;
1217 tasklet_init(&vlapic->init_sipi.tasklet,
1218 vlapic_init_sipi_action,
1219 (unsigned long)v);
1221 return 0;
1224 void vlapic_destroy(struct vcpu *v)
1226 struct vlapic *vlapic = vcpu_vlapic(v);
1228 tasklet_kill(&vlapic->init_sipi.tasklet);
1229 destroy_periodic_time(&vlapic->pt);
1230 unmap_domain_page_global(vlapic->regs);
1231 free_domheap_page(vlapic->regs_page);