direct-io.hg

view xen/arch/x86/hvm/vlapic.c @ 12350:5a4517468f4f

[HVM] Remove HVM halt timer. It's no longer needed since interrupts
can wake it up now.

Signed-off-by: Xin Li <xin.b.li@intel.com>
author kfraser@localhost.localdomain
date Fri Nov 10 11:01:15 2006 +0000 (2006-11-10)
parents 452010ddef24
children fda15861731e
line source
1 /*
2 * vlapic.c: virtualize LAPIC for HVM vcpus.
3 *
4 * Copyright (c) 2004, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 */
20 #include <xen/config.h>
21 #include <xen/types.h>
22 #include <xen/mm.h>
23 #include <xen/xmalloc.h>
24 #include <xen/shadow.h>
25 #include <xen/domain_page.h>
26 #include <asm/page.h>
27 #include <xen/event.h>
28 #include <xen/trace.h>
29 #include <asm/hvm/hvm.h>
30 #include <asm/hvm/io.h>
31 #include <asm/hvm/support.h>
32 #include <xen/lib.h>
33 #include <xen/sched.h>
34 #include <asm/current.h>
35 #include <public/hvm/ioreq.h>
36 #include <public/hvm/params.h>
38 #define VLAPIC_VERSION 0x00050014
39 #define VLAPIC_LVT_NUM 6
41 /* XXX remove this definition after GFW enabled */
42 #define VLAPIC_NO_BIOS
44 extern u32 get_apic_bus_cycle(void);
46 #define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000)
48 #define LVT_MASK \
49 APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
51 #define LINT_MASK \
52 LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\
53 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER
55 static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
56 {
57 /* LVTT */
58 LVT_MASK | APIC_LVT_TIMER_PERIODIC,
59 /* LVTTHMR */
60 LVT_MASK | APIC_MODE_MASK,
61 /* LVTPC */
62 LVT_MASK | APIC_MODE_MASK,
63 /* LVT0-1 */
64 LINT_MASK, LINT_MASK,
65 /* LVTERR */
66 LVT_MASK
67 };
69 /* Following could belong in apicdef.h */
70 #define APIC_SHORT_MASK 0xc0000
71 #define APIC_DEST_NOSHORT 0x0
72 #define APIC_DEST_MASK 0x800
74 #define vlapic_lvt_enabled(vlapic, lvt_type) \
75 (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED))
77 #define vlapic_lvt_vector(vlapic, lvt_type) \
78 (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
80 #define vlapic_lvt_dm(vlapic, lvt_type) \
81 (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
83 #define vlapic_lvtt_period(vlapic) \
84 (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
86 /*
87 * Generic APIC bitmap vector update & search routines.
88 */
90 #define VEC_POS(v) ((v)%32)
91 #define REG_POS(v) (((v)/32)* 0x10)
92 #define vlapic_test_and_set_vector(vec, bitmap) \
93 test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
94 #define vlapic_test_and_clear_vector(vec, bitmap) \
95 test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
96 #define vlapic_set_vector(vec, bitmap) \
97 set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
98 #define vlapic_clear_vector(vec, bitmap) \
99 clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec))
101 static int vlapic_find_highest_vector(u32 *bitmap)
102 {
103 int word_offset = MAX_VECTOR / 32;
105 /* Work backwards through the bitmap (first 32-bit word in every four). */
106 while ( (word_offset != 0) && (bitmap[(--word_offset)*4] == 0) )
107 continue;
109 return (fls(bitmap[word_offset*4]) - 1) + (word_offset * 32);
110 }
113 /*
114 * IRR-specific bitmap update & search routines.
115 */
117 static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic)
118 {
119 vlapic->flush_tpr_threshold = 1;
120 return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
121 }
123 static void vlapic_set_irr(int vector, struct vlapic *vlapic)
124 {
125 vlapic->flush_tpr_threshold = 1;
126 vlapic_set_vector(vector, vlapic->regs + APIC_IRR);
127 }
129 static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
130 {
131 vlapic->flush_tpr_threshold = 1;
132 vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
133 }
135 int vlapic_find_highest_irr(struct vlapic *vlapic)
136 {
137 int result;
139 result = vlapic_find_highest_vector(vlapic->regs + APIC_IRR);
140 ASSERT((result == -1) || (result >= 16));
142 return result;
143 }
146 int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
147 {
148 int ret;
150 ret = vlapic_test_and_set_irr(vec, vlapic);
151 if ( trig )
152 vlapic_set_vector(vec, vlapic->regs + APIC_TMR);
154 /* We may need to wake up target vcpu, besides set pending bit here */
155 return ret;
156 }
158 s_time_t get_apictime_scheduled(struct vcpu *v)
159 {
160 struct vlapic *vlapic = vcpu_vlapic(v);
162 if ( !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
163 return -1;
165 return vlapic->vlapic_timer.expires;
166 }
168 int vlapic_find_highest_isr(struct vlapic *vlapic)
169 {
170 int result;
172 result = vlapic_find_highest_vector(vlapic->regs + APIC_ISR);
173 ASSERT((result == -1) || (result >= 16));
175 return result;
176 }
178 uint32_t vlapic_get_ppr(struct vlapic *vlapic)
179 {
180 uint32_t tpr, isrv, ppr;
181 int isr;
183 tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
184 isr = vlapic_find_highest_isr(vlapic);
185 isrv = (isr != -1) ? isr : 0;
187 if ( (tpr & 0xf0) >= (isrv & 0xf0) )
188 ppr = tpr & 0xff;
189 else
190 ppr = isrv & 0xf0;
192 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
193 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.",
194 vlapic, ppr, isr, isrv);
196 return ppr;
197 }
199 /* This only for fixed delivery mode */
200 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
201 int short_hand, int dest, int dest_mode,
202 int delivery_mode)
203 {
204 int result = 0;
205 struct vlapic *target = vcpu_vlapic(v);
207 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
208 "dest_mode 0x%x, short_hand 0x%x, delivery_mode 0x%x.",
209 target, source, dest, dest_mode, short_hand, delivery_mode);
211 if ( unlikely(target == NULL) &&
212 ((delivery_mode != APIC_DM_INIT) &&
213 (delivery_mode != APIC_DM_STARTUP) &&
214 (delivery_mode != APIC_DM_NMI)) )
215 {
216 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, "
217 "delivery_mode 0x%x, dest 0x%x.\n",
218 v, delivery_mode, dest);
219 return result;
220 }
222 switch ( short_hand )
223 {
224 case APIC_DEST_NOSHORT: /* no shorthand */
225 if ( !dest_mode ) /* Physical */
226 {
227 result = ( ((target != NULL) ?
228 GET_APIC_ID(vlapic_get_reg(target, APIC_ID)):
229 v->vcpu_id)) == dest;
230 }
231 else /* Logical */
232 {
233 uint32_t ldr;
234 if ( target == NULL )
235 break;
236 ldr = vlapic_get_reg(target, APIC_LDR);
238 /* Flat mode */
239 if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT )
240 {
241 result = GET_APIC_LOGICAL_ID(ldr) & dest;
242 }
243 else
244 {
245 if ( (delivery_mode == APIC_DM_LOWEST) &&
246 (dest == 0xff) )
247 {
248 /* What shall we do now? */
249 gdprintk(XENLOG_ERR, "Broadcast IPI with lowest priority "
250 "delivery mode\n");
251 domain_crash_synchronous();
252 }
253 result = ((GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ?
254 (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0);
255 }
256 }
257 break;
259 case APIC_DEST_SELF:
260 if ( target == source )
261 result = 1;
262 break;
264 case APIC_DEST_ALLINC:
265 result = 1;
266 break;
268 case APIC_DEST_ALLBUT:
269 if ( target != source )
270 result = 1;
271 break;
273 default:
274 break;
275 }
277 return result;
278 }
280 /*
281 * Add a pending IRQ into lapic.
282 * Return 1 if successfully added and 0 if discarded.
283 */
284 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
285 int vector, int level, int trig_mode)
286 {
287 int result = 0;
288 struct vlapic *vlapic = vcpu_vlapic(v);
290 switch ( delivery_mode )
291 {
292 case APIC_DM_FIXED:
293 case APIC_DM_LOWEST:
294 /* FIXME add logic for vcpu on reset */
295 if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
296 break;
298 if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
299 {
300 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
301 "level trig mode repeatedly for vector %d\n", vector);
302 break;
303 }
305 if ( trig_mode )
306 {
307 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
308 "level trig mode for vector %d\n", vector);
309 vlapic_set_vector(vector, vlapic->regs + APIC_TMR);
310 }
312 vcpu_kick(v);
314 result = 1;
315 break;
317 case APIC_DM_REMRD:
318 gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3\n");
319 break;
321 case APIC_DM_SMI:
322 case APIC_DM_NMI:
323 gdprintk(XENLOG_WARNING, "Ignoring guest SMI/NMI\n");
324 break;
326 case APIC_DM_INIT:
327 /* No work on INIT de-assert for P4-type APIC. */
328 if ( trig_mode && !(level & APIC_INT_ASSERT) )
329 break;
330 /* FIXME How to check the situation after vcpu reset? */
331 if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
332 {
333 gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n");
334 domain_crash_synchronous();
335 }
336 v->arch.hvm_vcpu.init_sipi_sipi_state =
337 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
338 result = 1;
339 break;
341 case APIC_DM_STARTUP:
342 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
343 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
344 break;
346 v->arch.hvm_vcpu.init_sipi_sipi_state =
347 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
349 if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
350 {
351 gdprintk(XENLOG_ERR, "SIPI for initialized vcpu %x\n", v->vcpu_id);
352 domain_crash_synchronous();
353 }
355 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
356 result = 0;
357 break;
359 default:
360 gdprintk(XENLOG_ERR, "TODO: unsupported delivery mode %x\n",
361 delivery_mode);
362 domain_crash_synchronous();
363 break;
364 }
366 return result;
367 }
369 /* This function is used by both ioapic and lapic.The bitmap is for vcpu_id. */
370 struct vlapic *apic_round_robin(
371 struct domain *d, uint8_t vector, uint32_t bitmap)
372 {
373 int next, old;
374 struct vlapic *target = NULL;
376 spin_lock(&d->arch.hvm_domain.round_robin_lock);
378 old = next = d->arch.hvm_domain.round_info[vector];
380 /* the vcpu array is arranged according to vcpu_id */
381 do {
382 if ( ++next == MAX_VIRT_CPUS )
383 next = 0;
384 if ( (d->vcpu[next] == NULL) ||
385 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) )
386 continue;
388 if ( test_bit(next, &bitmap) )
389 {
390 target = vcpu_vlapic(d->vcpu[next]);
391 if ( vlapic_enabled(target) )
392 break;
393 target = NULL;
394 }
395 } while ( next != old );
397 d->arch.hvm_domain.round_info[vector] = next;
398 spin_unlock(&d->arch.hvm_domain.round_robin_lock);
400 return target;
401 }
403 void vlapic_EOI_set(struct vlapic *vlapic)
404 {
405 int vector = vlapic_find_highest_isr(vlapic);
407 /* Not every write EOI will has correpsoning ISR,
408 one example is when Kernel check timer on setup_IO_APIC */
409 if ( vector == -1 )
410 return ;
412 vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
414 if ( vlapic_test_and_clear_vector(vector, vlapic->regs + APIC_TMR) )
415 vioapic_update_EOI(vlapic_domain(vlapic), vector);
416 }
418 static void vlapic_ipi(struct vlapic *vlapic)
419 {
420 uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR);
421 uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2);
423 unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
424 unsigned int short_hand = icr_low & APIC_SHORT_MASK;
425 unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
426 unsigned int level = icr_low & APIC_INT_ASSERT;
427 unsigned int dest_mode = icr_low & APIC_DEST_MASK;
428 unsigned int delivery_mode =icr_low & APIC_MODE_MASK;
429 unsigned int vector = icr_low & APIC_VECTOR_MASK;
431 struct vlapic *target;
432 struct vcpu *v;
433 uint32_t lpr_map = 0;
435 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
436 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
437 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x.",
438 icr_high, icr_low, short_hand, dest,
439 trig_mode, level, dest_mode, delivery_mode, vector);
441 for_each_vcpu ( vlapic_domain(vlapic), v )
442 {
443 if ( vlapic_match_dest(v, vlapic, short_hand,
444 dest, dest_mode, delivery_mode) )
445 {
446 if ( delivery_mode == APIC_DM_LOWEST)
447 set_bit(v->vcpu_id, &lpr_map);
448 else
449 vlapic_accept_irq(v, delivery_mode,
450 vector, level, trig_mode);
451 }
452 }
454 if ( delivery_mode == APIC_DM_LOWEST )
455 {
456 target = apic_round_robin(vlapic_domain(v), vector, lpr_map);
457 if ( target != NULL )
458 vlapic_accept_irq(vlapic_vcpu(target), delivery_mode,
459 vector, level, trig_mode);
460 }
461 }
463 static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
464 {
465 uint32_t counter_passed;
466 s_time_t passed, now = NOW();
467 uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT);
469 if ( unlikely(now <= vlapic->timer_last_update) )
470 {
471 passed = ~0x0LL - vlapic->timer_last_update + now;
472 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed.");
473 }
474 else
475 passed = now - vlapic->timer_last_update;
477 counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor);
479 tmcct -= counter_passed;
481 if ( tmcct <= 0 )
482 {
483 if ( unlikely(!vlapic_lvtt_period(vlapic)) )
484 {
485 tmcct = 0;
486 /* FIXME: should we add interrupt here? */
487 }
488 else
489 {
490 do {
491 tmcct += vlapic_get_reg(vlapic, APIC_TMICT);
492 } while ( tmcct <= 0 );
493 }
494 }
496 vlapic->timer_last_update = now;
497 vlapic_set_reg(vlapic, APIC_TMCCT, tmcct);
499 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
500 "timer initial count 0x%x, timer current count 0x%x, "
501 "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.",
502 vlapic_get_reg(vlapic, APIC_TMICT),
503 vlapic_get_reg(vlapic, APIC_TMCCT),
504 vlapic->timer_last_update, now, counter_passed);
506 return tmcct;
507 }
509 static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
510 {
511 /* Only bits 0, 1 and 3 are settable; others are MBZ. */
512 val &= 0xb;
513 vlapic_set_reg(vlapic, APIC_TDCR, val);
515 /* Update the demangled timer_divisor. */
516 val = ((val & 3) | ((val & 8) >> 1)) + 1;
517 vlapic->timer_divisor = 1 << (val & 7);
518 }
520 static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
521 unsigned int len, unsigned int *result)
522 {
523 ASSERT((len == 4) && (offset > 0) && (offset <= APIC_TDCR));
525 switch ( offset )
526 {
527 case APIC_PROCPRI:
528 *result = vlapic_get_ppr(vlapic);
529 break;
531 case APIC_TMCCT: /* Timer CCR */
532 *result = vlapic_get_tmcct(vlapic);
533 break;
535 default:
536 *result = vlapic_get_reg(vlapic, offset);
537 break;
538 }
539 }
541 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
542 unsigned long len)
543 {
544 unsigned int alignment;
545 unsigned int tmp;
546 unsigned long result;
547 struct vlapic *vlapic = vcpu_vlapic(v);
548 unsigned int offset = address - vlapic->base_address;
550 if ( offset > APIC_TDCR )
551 return 0;
553 /* some bugs on kernel cause read this with byte*/
554 if ( len != 4 )
555 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
556 "read with len=0x%lx, should be 4 instead.\n",
557 len);
559 alignment = offset & 0x3;
561 vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
562 switch ( len )
563 {
564 case 1:
565 result = *((unsigned char *)&tmp + alignment);
566 break;
568 case 2:
569 ASSERT( alignment != 3 );
570 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
571 break;
573 case 4:
574 ASSERT( alignment == 0 );
575 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
576 break;
578 default:
579 gdprintk(XENLOG_ERR, "Local APIC read with len=0x%lx, "
580 "should be 4 instead.\n", len);
581 domain_crash_synchronous();
582 break;
583 }
585 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
586 "and the result is 0x%lx.", offset, len, result);
588 return result;
589 }
591 static void vlapic_write(struct vcpu *v, unsigned long address,
592 unsigned long len, unsigned long val)
593 {
594 struct vlapic *vlapic = vcpu_vlapic(v);
595 unsigned int offset = address - vlapic->base_address;
597 if ( offset != 0xb0 )
598 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
599 "offset 0x%x with length 0x%lx, and value is 0x%lx.",
600 offset, len, val);
602 /*
603 * According to the IA32 Manual, all accesses should be 32 bits.
604 * Some OSes do 8- or 16-byte accesses, however.
605 */
606 if ( len != 4 )
607 {
608 unsigned int tmp;
609 unsigned char alignment;
611 gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
613 alignment = offset & 0x3;
614 tmp = vlapic_read(v, offset & ~0x3, 4);
616 switch ( len )
617 {
618 case 1:
619 val = (tmp & ~(0xff << (8*alignment))) |
620 ((val & 0xff) << (8*alignment));
621 break;
623 case 2:
624 if ( alignment & 1 )
625 {
626 gdprintk(XENLOG_ERR, "Uneven alignment error for "
627 "2-byte vlapic access\n");
628 domain_crash_synchronous();
629 }
631 val = (tmp & ~(0xffff << (8*alignment))) |
632 ((val & 0xffff) << (8*alignment));
633 break;
635 default:
636 gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
637 "should be 4 instead\n", len);
638 domain_crash_synchronous();
639 break;
640 }
641 }
643 offset &= 0xff0;
645 switch ( offset )
646 {
647 case APIC_ID: /* Local APIC ID */
648 vlapic_set_reg(vlapic, APIC_ID, val);
649 break;
651 case APIC_TASKPRI:
652 vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
653 vlapic->flush_tpr_threshold = 1;
654 break;
656 case APIC_EOI:
657 vlapic_EOI_set(vlapic);
658 break;
660 case APIC_LDR:
661 vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
662 break;
664 case APIC_DFR:
665 vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
666 break;
668 case APIC_SPIV:
669 vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
671 if ( !(val & APIC_SPIV_APIC_ENABLED) )
672 {
673 int i;
674 uint32_t lvt_val;
676 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
678 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
679 {
680 lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
681 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
682 lvt_val | APIC_LVT_MASKED);
683 }
685 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
686 == APIC_DM_EXTINT )
687 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
688 }
689 else
690 {
691 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
692 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
693 == APIC_DM_EXTINT )
694 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
695 }
696 break;
698 case APIC_ESR:
699 /* Nothing to do. */
700 break;
702 case APIC_ICR:
703 /* No delay here, so we always clear the pending bit*/
704 vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12));
705 vlapic_ipi(vlapic);
706 break;
708 case APIC_ICR2:
709 vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
710 break;
712 case APIC_LVTT: /* LVT Timer Reg */
713 case APIC_LVTTHMR: /* LVT Thermal Monitor */
714 case APIC_LVTPC: /* LVT Performance Counter */
715 case APIC_LVT0: /* LVT LINT0 Reg */
716 case APIC_LVT1: /* LVT Lint1 Reg */
717 case APIC_LVTERR: /* LVT Error Reg */
718 {
719 if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
720 val |= APIC_LVT_MASKED;
722 val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
724 vlapic_set_reg(vlapic, offset, val);
726 if ( (vlapic_vcpu(vlapic)->vcpu_id == 0) && (offset == APIC_LVT0) )
727 {
728 if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
729 if ( val & APIC_LVT_MASKED)
730 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
731 else
732 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
733 else
734 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
735 }
736 }
737 break;
739 case APIC_TMICT:
740 {
741 s_time_t now = NOW(), offset;
743 stop_timer(&vlapic->vlapic_timer);
745 vlapic_set_reg(vlapic, APIC_TMICT, val);
746 vlapic_set_reg(vlapic, APIC_TMCCT, val);
747 vlapic->timer_last_update = now;
749 offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val;
751 set_timer(&vlapic->vlapic_timer, now + offset);
753 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
754 "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
755 "timer initial count 0x%x, offset 0x%016"PRIx64", "
756 "expire @ 0x%016"PRIx64".",
757 APIC_BUS_CYCLE_NS, now,
758 vlapic_get_reg(vlapic, APIC_TMICT),
759 offset, now + offset);
760 }
761 break;
763 case APIC_TDCR:
764 vlapic_set_tdcr(vlapic, val & 0xb);
765 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
766 vlapic->timer_divisor);
767 break;
769 default:
770 gdprintk(XENLOG_WARNING,
771 "Local APIC Write to read-only register 0x%x\n", offset);
772 break;
773 }
774 }
776 static int vlapic_range(struct vcpu *v, unsigned long addr)
777 {
778 struct vlapic *vlapic = vcpu_vlapic(v);
780 return (vlapic_global_enabled(vlapic) &&
781 (addr >= vlapic->base_address) &&
782 (addr < vlapic->base_address + PAGE_SIZE));
783 }
785 struct hvm_mmio_handler vlapic_mmio_handler = {
786 .check_handler = vlapic_range,
787 .read_handler = vlapic_read,
788 .write_handler = vlapic_write
789 };
791 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
792 {
793 vlapic->apic_base_msr = value;
794 vlapic->base_address = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE;
796 if ( !(value & MSR_IA32_APICBASE_ENABLE) )
797 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
798 else
799 clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
801 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
802 "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
803 vlapic->apic_base_msr, vlapic->base_address);
804 }
806 void vlapic_timer_fn(void *data)
807 {
808 struct vlapic *vlapic = data;
809 uint32_t timer_vector;
810 s_time_t now;
812 if ( unlikely(!vlapic_enabled(vlapic) ||
813 !vlapic_lvt_enabled(vlapic, APIC_LVTT)) )
814 return;
816 timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT);
817 now = NOW();
819 vlapic->timer_last_update = now;
821 if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
822 vlapic->timer_pending_count++;
824 if ( vlapic_lvtt_period(vlapic) )
825 {
826 s_time_t offset;
827 uint32_t tmict = vlapic_get_reg(vlapic, APIC_TMICT);
829 vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
831 offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict;
833 set_timer(&vlapic->vlapic_timer, now + offset);
834 }
835 else
836 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
838 vcpu_kick(vlapic_vcpu(vlapic));
840 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
841 "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
842 "timer initial count 0x%x, timer current count 0x%x.",
843 now, vlapic->vlapic_timer.expires,
844 vlapic_get_reg(vlapic, APIC_TMICT),
845 vlapic_get_reg(vlapic, APIC_TMCCT));
846 }
848 int vlapic_accept_pic_intr(struct vcpu *v)
849 {
850 struct vlapic *vlapic = vcpu_vlapic(v);
852 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
853 }
855 int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
856 {
857 struct vlapic *vlapic = vcpu_vlapic(v);
858 int highest_irr;
860 if ( !vlapic || !vlapic_enabled(vlapic) )
861 return -1;
863 highest_irr = vlapic_find_highest_irr(vlapic);
864 if ( (highest_irr == -1) ||
865 ((highest_irr & 0xF0) <= vlapic_get_ppr(vlapic)) )
866 return -1;
868 *mode = APIC_DM_FIXED;
869 return highest_irr;
870 }
872 /* check to see if there is pending interrupt */
873 int cpu_has_pending_irq(struct vcpu *v)
874 {
875 struct hvm_domain *plat = &v->domain->arch.hvm_domain;
876 int dummy;
878 /* APIC */
879 if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
880 return 1;
882 /* PIC */
883 if ( !vlapic_accept_pic_intr(v) )
884 return 0;
886 return plat->interrupt_request;
887 }
889 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
890 {
891 struct vlapic *vlapic = vcpu_vlapic(v);
893 if ( unlikely(vlapic == NULL) )
894 return;
896 switch ( deliver_mode )
897 {
898 case APIC_DM_FIXED:
899 case APIC_DM_LOWEST:
900 vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
901 vlapic_clear_irr(vector, vlapic);
902 if ( (vector == vlapic_lvt_vector(vlapic, APIC_LVTT)) &&
903 (vlapic->timer_pending_count != 0) )
904 {
905 vlapic->timer_pending_count--;
906 vlapic_set_irr(vector, vlapic);
907 }
908 break;
910 case APIC_DM_REMRD:
911 gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3.\n");
912 break;
914 case APIC_DM_SMI:
915 case APIC_DM_NMI:
916 case APIC_DM_INIT:
917 case APIC_DM_STARTUP:
918 break;
920 default:
921 gdprintk(XENLOG_WARNING, "Invalid delivery mode\n");
922 break;
923 }
924 }
926 static int vlapic_reset(struct vlapic *vlapic)
927 {
928 struct vcpu *v = vlapic_vcpu(vlapic);
929 int i;
931 vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
933 vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
935 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
936 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
938 vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
940 vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
942 vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
944 vlapic->flush_tpr_threshold = 0;
946 vlapic_set_tdcr(vlapic, 0);
948 vlapic->base_address = vlapic->apic_base_msr &
949 MSR_IA32_APICBASE_BASE;
951 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
952 "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
953 "base_address=0x%0lx.",
954 v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
955 vlapic->apic_base_msr, vlapic->base_address);
957 return 1;
958 }
960 int vlapic_init(struct vcpu *v)
961 {
962 struct vlapic *vlapic = vcpu_vlapic(v);
964 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
966 vlapic->regs_page = alloc_domheap_page(NULL);
967 if ( vlapic->regs_page == NULL )
968 {
969 dprintk(XENLOG_ERR, "malloc vlapic regs error for vcpu %x\n",
970 v->vcpu_id);
971 xfree(vlapic);
972 return -ENOMEM;
973 }
975 vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
976 memset(vlapic->regs, 0, PAGE_SIZE);
978 vlapic_reset(vlapic);
980 if ( v->vcpu_id == 0 )
981 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
983 init_timer(&vlapic->vlapic_timer,
984 vlapic_timer_fn, vlapic, v->processor);
986 #ifdef VLAPIC_NO_BIOS
987 /* According to mp specification, BIOS will enable LVT0/1. */
988 if ( v->vcpu_id == 0 )
989 {
990 vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
991 vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
992 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
993 }
994 #endif
996 return 0;
997 }
999 void vlapic_destroy(struct vcpu *v)
1001 struct vlapic *vlapic = vcpu_vlapic(v);
1003 kill_timer(&vlapic->vlapic_timer);
1004 unmap_domain_page_global(vlapic->regs);
1005 free_domheap_page(vlapic->regs_page);