direct-io.hg

view xen/arch/x86/hvm/vlapic.c @ 12235:b21ff7716f87

[HVM] More printk cleanups.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Nov 03 12:32:26 2006 +0000 (2006-11-03)
parents ceedd98b9afb
children 2368e779f89f
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 int hvm_apic_support(struct domain *d)
159 {
160 return d->arch.hvm_domain.params[HVM_PARAM_APIC_ENABLED];
161 }
163 s_time_t get_apictime_scheduled(struct vcpu *v)
164 {
165 struct vlapic *vlapic = VLAPIC(v);
167 if ( !hvm_apic_support(v->domain) ||
168 !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
169 return -1;
171 return vlapic->vlapic_timer.expires;
172 }
174 int vlapic_find_highest_isr(struct vlapic *vlapic)
175 {
176 int result;
178 result = vlapic_find_highest_vector(vlapic->regs + APIC_ISR);
179 ASSERT((result == -1) || (result >= 16));
181 return result;
182 }
184 uint32_t vlapic_get_ppr(struct vlapic *vlapic)
185 {
186 uint32_t tpr, isrv, ppr;
187 int isr;
189 tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
190 isr = vlapic_find_highest_isr(vlapic);
191 isrv = (isr != -1) ? isr : 0;
193 if ( (tpr & 0xf0) >= (isrv & 0xf0) )
194 ppr = tpr & 0xff;
195 else
196 ppr = isrv & 0xf0;
198 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
199 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.",
200 vlapic, ppr, isr, isrv);
202 return ppr;
203 }
205 /* This only for fixed delivery mode */
206 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
207 int short_hand, int dest, int dest_mode,
208 int delivery_mode)
209 {
210 int result = 0;
211 struct vlapic *target = VLAPIC(v);
213 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
214 "dest_mode 0x%x, short_hand 0x%x, delivery_mode 0x%x.",
215 target, source, dest, dest_mode, short_hand, delivery_mode);
217 if ( unlikely(target == NULL) &&
218 ((delivery_mode != APIC_DM_INIT) &&
219 (delivery_mode != APIC_DM_STARTUP) &&
220 (delivery_mode != APIC_DM_NMI)) )
221 {
222 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, "
223 "delivery_mode 0x%x, dest 0x%x.\n",
224 v, delivery_mode, dest);
225 return result;
226 }
228 switch ( short_hand )
229 {
230 case APIC_DEST_NOSHORT: /* no shorthand */
231 if ( !dest_mode ) /* Physical */
232 {
233 result = ( ((target != NULL) ?
234 GET_APIC_ID(vlapic_get_reg(target, APIC_ID)):
235 v->vcpu_id)) == dest;
236 }
237 else /* Logical */
238 {
239 uint32_t ldr;
240 if ( target == NULL )
241 break;
242 ldr = vlapic_get_reg(target, APIC_LDR);
244 /* Flat mode */
245 if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT )
246 {
247 result = GET_APIC_LOGICAL_ID(ldr) & dest;
248 }
249 else
250 {
251 if ( (delivery_mode == APIC_DM_LOWEST) &&
252 (dest == 0xff) )
253 {
254 /* What shall we do now? */
255 printk("Broadcast IPI with lowest priority "
256 "delivery mode\n");
257 domain_crash_synchronous();
258 }
259 result = ((GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ?
260 (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0);
261 }
262 }
263 break;
265 case APIC_DEST_SELF:
266 if ( target == source )
267 result = 1;
268 break;
270 case APIC_DEST_ALLINC:
271 result = 1;
272 break;
274 case APIC_DEST_ALLBUT:
275 if ( target != source )
276 result = 1;
277 break;
279 default:
280 break;
281 }
283 return result;
284 }
286 /*
287 * Add a pending IRQ into lapic.
288 * Return 1 if successfully added and 0 if discarded.
289 */
290 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
291 int vector, int level, int trig_mode)
292 {
293 int result = 0;
294 struct vlapic *vlapic = VLAPIC(v);
296 switch ( delivery_mode ) {
297 case APIC_DM_FIXED:
298 case APIC_DM_LOWEST:
299 /* FIXME add logic for vcpu on reset */
300 if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
301 break;
303 if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
304 {
305 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
306 "level trig mode repeatedly for vector %d\n", vector);
307 break;
308 }
310 if ( trig_mode )
311 {
312 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
313 "level trig mode for vector %d\n", vector);
314 vlapic_set_vector(vector, vlapic->regs + APIC_TMR);
315 }
317 vcpu_kick(v);
319 result = 1;
320 break;
322 case APIC_DM_REMRD:
323 printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
324 break;
326 case APIC_DM_SMI:
327 case APIC_DM_NMI:
328 /* Fixme */
329 printk("TODO: for guest SMI/NMI\n");
330 break;
332 case APIC_DM_INIT:
333 /* No work on INIT de-assert for P4-type APIC. */
334 if ( trig_mode && !(level & APIC_INT_ASSERT) )
335 break;
336 /* FIXME How to check the situation after vcpu reset? */
337 if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
338 {
339 gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n");
340 domain_crash_synchronous();
341 }
342 v->arch.hvm_vcpu.init_sipi_sipi_state =
343 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
344 result = 1;
345 break;
347 case APIC_DM_STARTUP:
348 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
349 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
350 break;
352 v->arch.hvm_vcpu.init_sipi_sipi_state =
353 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
355 if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
356 {
357 printk("SIPI for initialized vcpu vcpuid %x\n", v->vcpu_id);
358 domain_crash_synchronous();
359 }
361 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
362 result = 0;
363 break;
365 default:
366 printk("TODO: not support interrupt type %x\n", delivery_mode);
367 domain_crash_synchronous();
368 break;
369 }
371 return result;
372 }
374 /*
375 * This function is used by both ioapic and local APIC
376 * The bitmap is for vcpu_id
377 */
378 struct vlapic *apic_round_robin(struct domain *d,
379 uint8_t dest_mode,
380 uint8_t vector,
381 uint32_t bitmap)
382 {
383 int next, old;
384 struct vlapic* target = NULL;
386 if ( dest_mode == 0 ) /* Physical mode */
387 {
388 printk("<apic_round_robin> lowest priority for physical mode.\n");
389 return NULL;
390 }
392 if ( !bitmap )
393 {
394 printk("<apic_round_robin> no bit set in bitmap.\n");
395 return NULL;
396 }
398 spin_lock(&d->arch.hvm_domain.round_robin_lock);
400 old = next = d->arch.hvm_domain.round_info[vector];
402 /* the vcpu array is arranged according to vcpu_id */
403 do
404 {
405 if ( ++next == MAX_VIRT_CPUS )
406 next = 0;
407 if ( d->vcpu[next] == NULL ||
408 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) )
409 continue;
411 if ( test_bit(next, &bitmap) )
412 {
413 target = d->vcpu[next]->arch.hvm_vcpu.vlapic;
415 if ( target == NULL || !vlapic_enabled(target) )
416 {
417 printk("warning: targe round robin local apic disabled\n");
418 /* XXX should we domain crash?? Or should we return NULL */
419 }
420 break;
421 }
422 } while ( next != old );
424 d->arch.hvm_domain.round_info[vector] = next;
425 spin_unlock(&d->arch.hvm_domain.round_robin_lock);
427 return target;
428 }
430 void vlapic_EOI_set(struct vlapic *vlapic)
431 {
432 int vector = vlapic_find_highest_isr(vlapic);
434 /* Not every write EOI will has correpsoning ISR,
435 one example is when Kernel check timer on setup_IO_APIC */
436 if ( vector == -1 )
437 return ;
439 vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
441 if ( vlapic_test_and_clear_vector(vector, vlapic->regs + APIC_TMR) )
442 ioapic_update_EOI(vlapic->domain, vector);
443 }
445 static void vlapic_ipi(struct vlapic *vlapic)
446 {
447 uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR);
448 uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2);
450 unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
451 unsigned int short_hand = icr_low & APIC_SHORT_MASK;
452 unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
453 unsigned int level = icr_low & APIC_INT_ASSERT;
454 unsigned int dest_mode = icr_low & APIC_DEST_MASK;
455 unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
456 unsigned int vector = icr_low & APIC_VECTOR_MASK;
458 struct vlapic *target;
459 struct vcpu *v = NULL;
460 uint32_t lpr_map=0;
462 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
463 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
464 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x.",
465 icr_high, icr_low, short_hand, dest,
466 trig_mode, level, dest_mode, delivery_mode, vector);
468 for_each_vcpu ( vlapic->domain, v )
469 {
470 if ( vlapic_match_dest(v, vlapic, short_hand,
471 dest, dest_mode, delivery_mode) )
472 {
473 if ( delivery_mode == APIC_DM_LOWEST)
474 set_bit(v->vcpu_id, &lpr_map);
475 else
476 vlapic_accept_irq(v, delivery_mode,
477 vector, level, trig_mode);
478 }
479 }
481 if ( delivery_mode == APIC_DM_LOWEST)
482 {
483 v = vlapic->vcpu;
484 target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
486 if ( target )
487 vlapic_accept_irq(target->vcpu, delivery_mode,
488 vector, level, trig_mode);
489 }
490 }
492 static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
493 {
494 uint32_t counter_passed;
495 s_time_t passed, now = NOW();
496 uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT);
498 ASSERT(vlapic != NULL);
500 if ( unlikely(now <= vlapic->timer_last_update) )
501 {
502 passed = ~0x0LL - vlapic->timer_last_update + now;
503 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed.");
504 }
505 else
506 passed = now - vlapic->timer_last_update;
508 counter_passed = passed /
509 (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
511 tmcct -= counter_passed;
513 if ( tmcct <= 0 )
514 {
515 if ( unlikely(!vlapic_lvtt_period(vlapic)) )
516 {
517 tmcct = 0;
518 /* FIXME: should we add interrupt here? */
519 }
520 else
521 {
522 do {
523 tmcct += vlapic_get_reg(vlapic, APIC_TMICT);
524 } while ( tmcct <= 0 );
525 }
526 }
528 vlapic->timer_last_update = now;
529 vlapic_set_reg(vlapic, APIC_TMCCT, tmcct);
531 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
532 "timer initial count 0x%x, timer current count 0x%x, "
533 "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.",
534 vlapic_get_reg(vlapic, APIC_TMICT),
535 vlapic_get_reg(vlapic, APIC_TMCCT),
536 vlapic->timer_last_update, now, counter_passed);
538 return tmcct;
539 }
541 static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
542 unsigned int len, unsigned int *result)
543 {
544 ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR);
546 *result = 0;
548 switch ( offset ) {
549 case APIC_PROCPRI:
550 *result = vlapic_get_ppr(vlapic);
551 break;
553 case APIC_ARBPRI:
554 printk("access local APIC ARBPRI register which is for P6\n");
555 break;
557 case APIC_TMCCT: /* Timer CCR */
558 *result = vlapic_get_tmcct(vlapic);
559 break;
561 default:
562 *result = vlapic_get_reg(vlapic, offset);
563 break;
564 }
565 }
567 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
568 unsigned long len)
569 {
570 unsigned int alignment;
571 unsigned int tmp;
572 unsigned long result;
573 struct vlapic *vlapic = VLAPIC(v);
574 unsigned int offset = address - vlapic->base_address;
576 if ( offset > APIC_TDCR)
577 return 0;
579 /* some bugs on kernel cause read this with byte*/
580 if ( len != 4 )
581 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
582 "read with len=0x%lx, should be 4 instead.\n",
583 len);
585 alignment = offset & 0x3;
587 vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
588 switch ( len ) {
589 case 1:
590 result = *((unsigned char *)&tmp + alignment);
591 break;
593 case 2:
594 ASSERT( alignment != 3 );
595 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
596 break;
598 case 4:
599 ASSERT( alignment == 0 );
600 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
601 break;
603 default:
604 printk("Local APIC read with len=0x%lx, should be 4 instead.\n", len);
605 domain_crash_synchronous();
606 break;
607 }
609 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
610 "and the result is 0x%lx.", offset, len, result);
612 return result;
613 }
615 static void vlapic_write(struct vcpu *v, unsigned long address,
616 unsigned long len, unsigned long val)
617 {
618 struct vlapic *vlapic = VLAPIC(v);
619 unsigned int offset = address - vlapic->base_address;
621 if ( offset != 0xb0 )
622 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
623 "offset 0x%x with length 0x%lx, and value is 0x%lx.",
624 offset, len, val);
626 /*
627 * According to the IA32 Manual, all accesses should be 32 bits.
628 * Some OSes do 8- or 16-byte accesses, however.
629 */
630 if ( len != 4 )
631 {
632 unsigned int tmp;
633 unsigned char alignment;
635 gdprintk(XENLOG_INFO, "Notice: Local APIC write with len = %lx\n",len);
637 alignment = offset & 0x3;
638 tmp = vlapic_read(v, offset & ~0x3, 4);
640 switch ( len )
641 {
642 case 1:
643 val = (tmp & ~(0xff << (8*alignment))) |
644 ((val & 0xff) << (8*alignment));
645 break;
647 case 2:
648 if ( alignment & 1 )
649 {
650 gdprintk(XENLOG_ERR, "Uneven alignment error for "
651 "2-byte vlapic access\n");
652 domain_crash_synchronous();
653 }
655 val = (tmp & ~(0xffff << (8*alignment))) |
656 ((val & 0xffff) << (8*alignment));
657 break;
659 default:
660 gdprintk(XENLOG_ERR, "Local APIC write with len = %lx, "
661 "should be 4 instead\n", len);
662 domain_crash_synchronous();
663 break;
664 }
665 }
667 offset &= 0xff0;
669 switch ( offset )
670 {
671 case APIC_ID: /* Local APIC ID */
672 vlapic_set_reg(vlapic, APIC_ID, val);
673 break;
675 case APIC_TASKPRI:
676 vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
677 vlapic->flush_tpr_threshold = 1;
678 break;
680 case APIC_EOI:
681 vlapic_EOI_set(vlapic);
682 break;
684 case APIC_LDR:
685 vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
686 break;
688 case APIC_DFR:
689 vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF);
690 break;
692 case APIC_SPIV:
693 vlapic_set_reg(vlapic, APIC_SPIV, val & 0x3ff);
695 if ( !(val & APIC_SPIV_APIC_ENABLED) )
696 {
697 int i;
698 uint32_t lvt_val;
700 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
702 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
703 {
704 lvt_val = vlapic_get_reg(vlapic, APIC_LVTT + 0x10 * i);
705 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
706 lvt_val | APIC_LVT_MASKED);
707 }
709 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
710 == APIC_DM_EXTINT )
711 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
712 }
713 else
714 {
715 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
716 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
717 == APIC_DM_EXTINT )
718 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
719 }
720 break;
722 case APIC_ESR:
723 /* Nothing to do. */
724 break;
726 case APIC_ICR:
727 /* No delay here, so we always clear the pending bit*/
728 vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12));
729 vlapic_ipi(vlapic);
730 break;
732 case APIC_ICR2:
733 vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
734 break;
736 case APIC_LVTT: /* LVT Timer Reg */
737 case APIC_LVTTHMR: /* LVT Thermal Monitor */
738 case APIC_LVTPC: /* LVT Performance Counter */
739 case APIC_LVT0: /* LVT LINT0 Reg */
740 case APIC_LVT1: /* LVT Lint1 Reg */
741 case APIC_LVTERR: /* LVT Error Reg */
742 {
743 if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
744 val |= APIC_LVT_MASKED;
746 val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
748 vlapic_set_reg(vlapic, offset, val);
750 if ( !vlapic->vcpu->vcpu_id && (offset == APIC_LVT0) )
751 {
752 if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
753 if ( val & APIC_LVT_MASKED)
754 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
755 else
756 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
757 else
758 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
759 }
760 }
761 break;
763 case APIC_TMICT:
764 {
765 s_time_t now = NOW(), offset;
767 stop_timer(&vlapic->vlapic_timer);
769 vlapic_set_reg(vlapic, APIC_TMICT, val);
770 vlapic_set_reg(vlapic, APIC_TMCCT, val);
771 vlapic->timer_last_update = now;
773 offset = APIC_BUS_CYCLE_NS *
774 vlapic->timer_divide_count * val;
776 set_timer(&vlapic->vlapic_timer, now + offset);
778 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
779 "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
780 "timer initial count 0x%x, offset 0x%016"PRIx64", "
781 "expire @ 0x%016"PRIx64".",
782 APIC_BUS_CYCLE_NS, now,
783 vlapic_get_reg(vlapic, APIC_TMICT),
784 offset, now + offset);
785 }
786 break;
788 case APIC_TDCR:
789 {
790 unsigned int tmp1, tmp2;
792 tmp1 = val & 0xf;
793 tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
794 vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
796 vlapic_set_reg(vlapic, APIC_TDCR, val);
798 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
799 vlapic->timer_divide_count);
800 }
801 break;
803 default:
804 gdprintk(XENLOG_WARNING,
805 "Local APIC Write to read-only register 0x%x\n", offset);
806 break;
807 }
808 }
810 static int vlapic_range(struct vcpu *v, unsigned long addr)
811 {
812 struct vlapic *vlapic = VLAPIC(v);
814 return (vlapic_global_enabled(vlapic) &&
815 (addr >= vlapic->base_address) &&
816 (addr < vlapic->base_address + PAGE_SIZE));
817 }
819 struct hvm_mmio_handler vlapic_mmio_handler = {
820 .check_handler = vlapic_range,
821 .read_handler = vlapic_read,
822 .write_handler = vlapic_write
823 };
825 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
826 {
827 if ( vlapic == NULL )
828 return;
830 if ( vlapic->vcpu->vcpu_id )
831 value &= ~MSR_IA32_APICBASE_BSP;
833 vlapic->apic_base_msr = value;
834 vlapic->base_address = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE;
836 if ( !(value & MSR_IA32_APICBASE_ENABLE) )
837 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
838 else
839 clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
841 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
842 "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
843 vlapic->apic_base_msr, vlapic->base_address);
844 }
846 void vlapic_timer_fn(void *data)
847 {
848 struct vlapic *vlapic = data;
849 struct vcpu *v;
850 uint32_t timer_vector;
851 s_time_t now;
853 if ( unlikely(!vlapic_enabled(vlapic) ||
854 !vlapic_lvt_enabled(vlapic, APIC_LVTT)) )
855 return;
857 v = vlapic->vcpu;
858 timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT);
859 now = NOW();
861 vlapic->timer_last_update = now;
863 if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
864 vlapic->timer_pending_count++;
866 if ( vlapic_lvtt_period(vlapic) )
867 {
868 s_time_t offset;
869 uint32_t tmict = vlapic_get_reg(vlapic, APIC_TMICT);
871 vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
873 offset = APIC_BUS_CYCLE_NS *
874 vlapic->timer_divide_count * tmict;
876 set_timer(&vlapic->vlapic_timer, now + offset);
877 }
878 else
879 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
881 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
882 "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
883 "timer initial count 0x%x, timer current count 0x%x.",
884 now, vlapic->vlapic_timer.expires,
885 vlapic_get_reg(vlapic, APIC_TMICT),
886 vlapic_get_reg(vlapic, APIC_TMCCT));
887 }
889 int vlapic_accept_pic_intr(struct vcpu *v)
890 {
891 struct vlapic *vlapic = VLAPIC(v);
893 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
894 }
896 int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
897 {
898 struct vlapic *vlapic = VLAPIC(v);
899 int highest_irr;
901 if ( !vlapic || !vlapic_enabled(vlapic) )
902 return -1;
904 highest_irr = vlapic_find_highest_irr(vlapic);
905 if ( (highest_irr == -1) ||
906 ((highest_irr & 0xF0) <= vlapic_get_ppr(vlapic)) )
907 return -1;
909 *mode = APIC_DM_FIXED;
910 return highest_irr;
911 }
913 /* check to see if there is pending interrupt */
914 int cpu_has_pending_irq(struct vcpu *v)
915 {
916 struct hvm_domain *plat = &v->domain->arch.hvm_domain;
917 int dummy;
919 /* APIC */
920 if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
921 return 1;
923 /* PIC */
924 if ( !vlapic_accept_pic_intr(v) )
925 return 0;
927 return plat->interrupt_request;
928 }
930 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
931 {
932 struct vlapic *vlapic = VLAPIC(v);
934 if ( unlikely(vlapic == NULL) )
935 return;
937 switch ( deliver_mode )
938 {
939 case APIC_DM_FIXED:
940 case APIC_DM_LOWEST:
941 vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
942 vlapic_clear_irr(vector, vlapic);
943 if ( (vector == vlapic_lvt_vector(vlapic, APIC_LVTT)) &&
944 (vlapic->timer_pending_count != 0) )
945 {
946 vlapic->timer_pending_count--;
947 vlapic_set_irr(vector, vlapic);
948 }
949 break;
951 /*XXX deal with these later */
952 case APIC_DM_REMRD:
953 printk("Ignore deliver mode 3 in vlapic_post_injection\n");
954 break;
956 case APIC_DM_SMI:
957 case APIC_DM_NMI:
958 case APIC_DM_INIT:
959 case APIC_DM_STARTUP:
960 break;
962 default:
963 printk("<vlapic_post_injection> invalid deliver mode\n");
964 break;
965 }
966 }
968 static int vlapic_reset(struct vlapic *vlapic)
969 {
970 struct vcpu *v = vlapic->vcpu;
971 int i;
973 vlapic->domain = v->domain;
975 vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
977 vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
979 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
980 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
982 vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
984 vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
986 vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
988 vlapic->flush_tpr_threshold = 0;
990 if ( v->vcpu_id == 0 )
991 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
993 vlapic->base_address = vlapic->apic_base_msr &
994 MSR_IA32_APICBASE_BASE;
996 hvm_vioapic_add_lapic(vlapic, v);
998 init_timer(&vlapic->vlapic_timer,
999 vlapic_timer_fn, vlapic, v->processor);
1001 #ifdef VLAPIC_NO_BIOS
1002 /*
1003 * XXX According to mp sepcific, BIOS will enable LVT0/1,
1004 * remove it after BIOS enabled
1005 */
1006 if ( !v->vcpu_id )
1008 vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
1009 vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
1010 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
1012 #endif
1014 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
1015 "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
1016 "base_address=0x%0lx.",
1017 v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
1018 vlapic->apic_base_msr, vlapic->base_address);
1020 return 1;
1023 int vlapic_init(struct vcpu *v)
1025 struct vlapic *vlapic = NULL;
1027 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
1029 vlapic = xmalloc_bytes(sizeof(struct vlapic));
1030 if ( vlapic == NULL )
1032 printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
1033 return -ENOMEM;
1036 memset(vlapic, 0, sizeof(struct vlapic));
1038 vlapic->regs_page = alloc_domheap_page(NULL);
1039 if ( vlapic->regs_page == NULL )
1041 printk("malloc vlapic regs error for vcpu %x\n", v->vcpu_id);
1042 xfree(vlapic);
1043 return -ENOMEM;
1046 vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
1047 memset(vlapic->regs, 0, PAGE_SIZE);
1049 VLAPIC(v) = vlapic;
1050 vlapic->vcpu = v;
1052 vlapic_reset(vlapic);
1054 return 0;