ia64/xen-unstable

view xen/arch/x86/hvm/vlapic.c @ 10907:637b6d60e792

[HVM] Fix an issue with APIC priority checks.

Signed-off-by; Yunhong Jiang <yunhong.jiang@intel.com>
author kfraser@localhost.localdomain
date Wed Aug 02 10:04:27 2006 +0100 (2006-08-02)
parents ab0cae84cfec
children a6cb8ba24a91
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 <asm/shadow.h>
25 #include <asm/page.h>
26 #include <xen/event.h>
27 #include <xen/trace.h>
28 #include <asm/hvm/hvm.h>
29 #include <asm/hvm/io.h>
30 #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>
37 /* XXX remove this definition after GFW enabled */
38 #define VLAPIC_NO_BIOS
40 extern u32 get_apic_bus_cycle(void);
42 #define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000)
44 static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
45 {
46 0x310ff, 0x117ff, 0x117ff, 0x1f7ff, 0x1f7ff, 0x117ff
47 };
49 int vlapic_find_highest_irr(struct vlapic *vlapic)
50 {
51 int result;
53 result = find_highest_bit(vlapic->irr, MAX_VECTOR);
55 if ( result != -1 && result < 16 )
56 {
57 printk("VLAPIC: irr on reserved bits %d\n ", result);
58 domain_crash_synchronous();
59 }
61 return result;
62 }
64 int hvm_apic_support(struct domain *d)
65 {
66 return d->arch.hvm_domain.apic_enabled;
67 }
69 s_time_t get_apictime_scheduled(struct vcpu *v)
70 {
71 struct vlapic *vlapic = VLAPIC(v);
73 if ( !hvm_apic_support(v->domain) || !vlapic_lvt_timer_enabled(vlapic) )
74 return -1;
75 return vlapic->vlapic_timer.expires;
76 }
78 int vlapic_find_highest_isr(struct vlapic *vlapic)
79 {
80 int result;
82 result = find_highest_bit(vlapic->isr, MAX_VECTOR);
84 if ( result != -1 && result < 16 )
85 {
86 int i = 0;
87 printk("VLAPIC: isr on reserved bits %d, isr is\n ", result);
88 for ( i = 0; i < ARRAY_SIZE(vlapic->isr); i++ )
89 printk("%d: %p\n", i, (void *)vlapic->isr[i]);
90 return -1;
91 }
93 return result;
94 }
96 uint32_t vlapic_update_ppr(struct vlapic *vlapic)
97 {
98 uint32_t tpr, isrv, ppr;
99 int isr;
101 tpr = (vlapic->task_priority >> 4) & 0xf; /* we want 7:4 */
103 isr = vlapic_find_highest_isr(vlapic);
104 if ( isr != -1 )
105 isrv = (isr >> 4) & 0xf; /* ditto */
106 else
107 isrv = 0;
109 if ( tpr >= isrv )
110 ppr = vlapic->task_priority & 0xff;
111 else
112 ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */
114 vlapic->processor_priority = ppr;
116 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
117 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.",
118 vlapic, ppr, isr, isrv);
120 return ppr;
121 }
123 /* This only for fixed delivery mode */
124 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
125 int short_hand, int dest, int dest_mode,
126 int delivery_mode)
127 {
128 int result = 0;
129 struct vlapic *target = VLAPIC(v);
131 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
132 "dest_mode 0x%x, short_hand 0x%x, delivery_mode 0x%x.",
133 target, source, dest, dest_mode, short_hand, delivery_mode);
135 if ( unlikely(target == NULL) &&
136 ((delivery_mode != VLAPIC_DELIV_MODE_INIT) &&
137 (delivery_mode != VLAPIC_DELIV_MODE_STARTUP) &&
138 (delivery_mode != VLAPIC_DELIV_MODE_NMI)) )
139 {
140 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, "
141 "delivery_mode 0x%x, dest 0x%x.\n", v, delivery_mode, dest);
142 return result;
143 }
145 switch ( short_hand ) {
146 case VLAPIC_NO_SHORTHAND:
147 if ( !dest_mode ) /* Physical */
148 {
149 result = (target != NULL ? target->id : v->vcpu_id) == dest;
150 }
151 else /* Logical */
152 {
153 if ( target == NULL )
154 break;
155 if ( ((target->dest_format >> 28) & 0xf) == 0xf ) /* Flat mode */
156 {
157 result = (target->logical_dest >> 24) & dest;
158 }
159 else
160 {
161 if ( (delivery_mode == VLAPIC_DELIV_MODE_LPRI) &&
162 (dest == 0xff) )
163 {
164 /* What shall we do now? */
165 printk("Broadcast IPI with lowest priority "
166 "delivery mode\n");
167 domain_crash_synchronous();
168 }
169 result = (target->logical_dest == (dest & 0xf)) ?
170 ((target->logical_dest >> 4) & (dest >> 4)) : 0;
171 }
172 }
173 break;
175 case VLAPIC_SHORTHAND_SELF:
176 if ( target == source )
177 result = 1;
178 break;
180 case VLAPIC_SHORTHAND_INCLUDE_SELF:
181 result = 1;
182 break;
184 case VLAPIC_SHORTHAND_EXCLUDE_SELF:
185 if ( target != source )
186 result = 1;
187 break;
189 default:
190 break;
191 }
193 return result;
194 }
196 /*
197 * Add a pending IRQ into lapic.
198 * Return 1 if successfully added and 0 if discarded.
199 */
200 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
201 int vector, int level, int trig_mode)
202 {
203 int result = 0;
204 struct vlapic *vlapic = VLAPIC(v);
206 switch ( delivery_mode ) {
207 case VLAPIC_DELIV_MODE_FIXED:
208 case VLAPIC_DELIV_MODE_LPRI:
209 /* FIXME add logic for vcpu on reset */
210 if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
211 break;
213 if ( test_and_set_bit(vector, &vlapic->irr[0]) && level)
214 {
215 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
216 "level trig mode repeatedly for vector %d\n", vector);
217 break;
218 }
220 if ( level )
221 {
222 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
223 "level trig mode for vector %d\n", vector);
224 set_bit(vector, &vlapic->tmr[0]);
225 }
226 evtchn_set_pending(v, iopacket_port(v));
228 result = 1;
229 break;
231 case VLAPIC_DELIV_MODE_RESERVED:
232 printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
233 break;
235 case VLAPIC_DELIV_MODE_SMI:
236 case VLAPIC_DELIV_MODE_NMI:
237 /* Fixme */
238 printk("TODO: for guest SMI/NMI\n");
239 break;
241 case VLAPIC_DELIV_MODE_INIT:
242 if ( !level && trig_mode == 1 ) //Deassert
243 printk("This hvm_vlapic is for P4, no work for De-assert init\n");
244 else
245 {
246 /* FIXME How to check the situation after vcpu reset? */
247 if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
248 {
249 printk("Reset hvm vcpu not supported yet\n");
250 domain_crash_synchronous();
251 }
252 v->arch.hvm_vcpu.init_sipi_sipi_state =
253 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
254 result = 1;
255 }
256 break;
258 case VLAPIC_DELIV_MODE_STARTUP:
259 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
260 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
261 break;
263 v->arch.hvm_vcpu.init_sipi_sipi_state =
264 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
266 if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
267 {
268 printk("SIPI for initialized vcpu vcpuid %x\n", v->vcpu_id);
269 domain_crash_synchronous();
270 }
272 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
273 result = 0;
274 break;
276 default:
277 printk("TODO: not support interrupt type %x\n", delivery_mode);
278 domain_crash_synchronous();
279 break;
280 }
282 return result;
283 }
284 /*
285 This function is used by both ioapic and local APIC
286 The bitmap is for vcpu_id
287 */
288 struct vlapic* apic_round_robin(struct domain *d,
289 uint8_t dest_mode,
290 uint8_t vector,
291 uint32_t bitmap)
292 {
293 int next, old;
294 struct vlapic* target = NULL;
296 if ( dest_mode == 0 ) //Physical mode
297 {
298 printk("<apic_round_robin> lowest priority for physical mode.\n");
299 return NULL;
300 }
302 if ( !bitmap )
303 {
304 printk("<apic_round_robin> no bit set in bitmap.\n");
305 return NULL;
306 }
308 spin_lock(&d->arch.hvm_domain.round_robin_lock);
310 old = next = d->arch.hvm_domain.round_info[vector];
312 /* the vcpu array is arranged according to vcpu_id */
313 do
314 {
315 next++;
316 if ( !d->vcpu[next] ||
317 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) ||
318 next == MAX_VIRT_CPUS )
319 next = 0;
321 if ( test_bit(next, &bitmap) )
322 {
323 target = d->vcpu[next]->arch.hvm_vcpu.vlapic;
325 if ( target == NULL || !vlapic_enabled(target) )
326 {
327 printk("warning: targe round robin local apic disabled\n");
328 /* XXX should we domain crash?? Or should we return NULL */
329 }
330 break;
331 }
332 } while ( next != old );
334 d->arch.hvm_domain.round_info[vector] = next;
335 spin_unlock(&d->arch.hvm_domain.round_robin_lock);
337 return target;
338 }
340 void vlapic_EOI_set(struct vlapic *vlapic)
341 {
342 int vector = vlapic_find_highest_isr(vlapic);
344 /* Not every write EOI will has correpsoning ISR,
345 one example is when Kernel check timer on setup_IO_APIC */
346 if ( vector == -1 )
347 return ;
349 clear_bit(vector, &vlapic->isr[0]);
350 vlapic_update_ppr(vlapic);
352 if ( test_and_clear_bit(vector, &vlapic->tmr[0]) )
353 ioapic_update_EOI(vlapic->domain, vector);
354 }
356 int vlapic_check_vector(struct vlapic *vlapic,
357 unsigned char dm, int vector)
358 {
359 if ( (dm == VLAPIC_DELIV_MODE_FIXED) && (vector < 16) )
360 {
361 vlapic->err_status |= 0x40;
362 vlapic_accept_irq(vlapic->vcpu, VLAPIC_DELIV_MODE_FIXED,
363 vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), 0, 0);
364 printk("<vlapic_check_vector>: check failed.\n");
365 return 0;
366 }
367 return 1;
368 }
370 void vlapic_ipi(struct vlapic *vlapic)
371 {
372 unsigned int dest = (vlapic->icr_high >> 24) & 0xff;
373 unsigned int short_hand = (vlapic->icr_low >> 18) & 3;
374 unsigned int trig_mode = (vlapic->icr_low >> 15) & 1;
375 unsigned int level = (vlapic->icr_low >> 14) & 1;
376 unsigned int dest_mode = (vlapic->icr_low >> 11) & 1;
377 unsigned int delivery_mode = (vlapic->icr_low >> 8) & 7;
378 unsigned int vector = (vlapic->icr_low & 0xff);
380 struct vlapic *target;
381 struct vcpu *v = NULL;
382 uint32_t lpr_map;
384 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
385 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
386 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x.",
387 vlapic->icr_high, vlapic->icr_low, short_hand, dest,
388 trig_mode, level, dest_mode, delivery_mode, vector);
390 for_each_vcpu ( vlapic->domain, v )
391 {
392 if ( vlapic_match_dest(v, vlapic, short_hand,
393 dest, dest_mode, delivery_mode) )
394 {
395 if ( delivery_mode == VLAPIC_DELIV_MODE_LPRI )
396 set_bit(v->vcpu_id, &lpr_map);
397 else
398 vlapic_accept_irq(v, delivery_mode,
399 vector, level, trig_mode);
400 }
401 }
403 if ( delivery_mode == VLAPIC_DELIV_MODE_LPRI )
404 {
405 v = vlapic->vcpu;
406 target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
408 if ( target )
409 vlapic_accept_irq(target->vcpu, delivery_mode,
410 vector, level, trig_mode);
411 }
412 }
414 static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
415 unsigned int len, unsigned int *result)
416 {
417 if ( len != 4 )
418 printk("<vlapic_read_aligned> read with len=%d (should be 4).\n", len);
420 *result = 0;
422 switch ( offset ) {
423 case APIC_ID:
424 *result = vlapic->id << 24;
425 break;
427 case APIC_LVR:
428 *result = vlapic->version;
429 break;
431 case APIC_TASKPRI:
432 *result = vlapic->task_priority;
433 break;
435 case APIC_ARBPRI:
436 printk("access local APIC ARBPRI register which is for P6\n");
437 break;
439 case APIC_PROCPRI:
440 *result = vlapic->processor_priority;
441 break;
443 case APIC_EOI: /* EOI is write only */
444 break;
446 case APIC_LDR:
447 *result = vlapic->logical_dest;
448 break;
450 case APIC_DFR:
451 *result = vlapic->dest_format;
452 break;
454 case APIC_SPIV:
455 *result = vlapic->spurious_vec;
456 break;
458 case APIC_ISR:
459 case 0x110:
460 case 0x120:
461 case 0x130:
462 case 0x140:
463 case 0x150:
464 case 0x160:
465 case 0x170:
466 *result = vlapic->isr[(offset - APIC_ISR) >> 4];
467 break;
469 case APIC_TMR:
470 case 0x190:
471 case 0x1a0:
472 case 0x1b0:
473 case 0x1c0:
474 case 0x1d0:
475 case 0x1e0:
476 case 0x1f0:
477 *result = vlapic->tmr[(offset - APIC_TMR) >> 4];
478 break;
480 case APIC_IRR:
481 case 0x210:
482 case 0x220:
483 case 0x230:
484 case 0x240:
485 case 0x250:
486 case 0x260:
487 case 0x270:
488 *result = vlapic->irr[(offset - APIC_IRR) >> 4];
489 break;
491 case APIC_ESR:
492 if ( vlapic->err_write_count )
493 *result = vlapic->err_status;
494 break;
496 case APIC_ICR:
497 *result = vlapic->icr_low;
498 break;
500 case APIC_ICR2:
501 *result = vlapic->icr_high;
502 break;
504 case APIC_LVTT: /* LVT Timer Reg */
505 case APIC_LVTTHMR: /* LVT Thermal Monitor */
506 case APIC_LVTPC: /* LVT Performance Counter */
507 case APIC_LVT0: /* LVT LINT0 Reg */
508 case APIC_LVT1: /* LVT Lint1 Reg */
509 case APIC_LVTERR: /* LVT Error Reg */
510 *result = vlapic->lvt[(offset - APIC_LVTT) >> 4];
511 break;
513 case APIC_TMICT:
514 *result = vlapic->timer_initial_count;
515 break;
517 case APIC_TMCCT: //Timer CCR
518 {
519 uint32_t counter_passed;
520 s_time_t passed, now = NOW();
522 if ( unlikely(now <= vlapic->timer_current_update) )
523 {
524 passed = ~0x0LL - vlapic->timer_current_update + now;
525 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed.");
526 }
527 else
528 passed = now - vlapic->timer_current_update;
530 counter_passed = passed /
531 (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
532 vlapic->timer_current_count -= counter_passed;
533 if ( vlapic->timer_current_count <= 0 )
534 {
535 if ( unlikely(!vlapic_lvt_timer_period(vlapic)) )
536 {
537 vlapic->timer_current_count = 0;
538 // FIXME: should we add interrupt here?
539 }
540 else
541 {
542 do {
543 vlapic->timer_current_count += vlapic->timer_initial_count;
544 } while ( vlapic->timer_current_count < 0 );
545 }
546 }
548 *result = vlapic->timer_current_count;
549 vlapic->timer_current_update = now;
551 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
552 "timer initial count 0x%x, timer current count 0x%x, "
553 "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.",
554 vlapic->timer_initial_count, vlapic->timer_current_count,
555 vlapic->timer_current_update, now, counter_passed);
556 }
557 break;
559 case APIC_TDCR:
560 *result = vlapic->timer_divconf;
561 break;
563 default:
564 printk("Read local APIC address 0x%x not implemented\n", offset);
565 *result = 0;
566 break;
567 }
568 }
570 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
571 unsigned long len)
572 {
573 unsigned int alignment;
574 unsigned int tmp;
575 unsigned long result;
576 struct vlapic *vlapic = VLAPIC(v);
577 unsigned int offset = address - vlapic->base_address;
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 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
595 break;
597 case 4:
598 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
599 break;
601 default:
602 printk("Local APIC read with len=0x%lx, should be 4 instead.\n", len);
603 domain_crash_synchronous();
604 break;
605 }
607 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
608 "and the result is 0x%lx.", offset, len, result);
610 return result;
611 }
613 static void vlapic_write(struct vcpu *v, unsigned long address,
614 unsigned long len, unsigned long val)
615 {
616 struct vlapic *vlapic = VLAPIC(v);
617 unsigned int offset = address - vlapic->base_address;
619 if ( offset != 0xb0 )
620 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
621 "offset 0x%x with length 0x%lx, and value is 0x%lx.",
622 offset, len, val);
624 /*
625 * According to IA 32 Manual, all resgiters should be accessed with
626 * 32 bits alignment.
627 */
628 if ( len != 4 )
629 {
630 unsigned int tmp;
631 unsigned char alignment;
633 /* Some kernel do will access with byte/word alignment*/
634 printk("Notice: Local APIC write with len = %lx\n",len);
635 alignment = offset & 0x3;
636 tmp = vlapic_read(v, offset & ~0x3, 4);
637 switch ( len ) {
638 case 1:
639 /* XXX the saddr is a tmp variable from caller, so should be ok
640 But we should still change the following ref to val to
641 local variable later */
642 val = (tmp & ~(0xff << alignment)) |
643 ((val & 0xff) << alignment);
644 break;
646 case 2:
647 if ( alignment != 0x0 && alignment != 0x2 )
648 {
649 printk("alignment error for vlapic with len == 2\n");
650 domain_crash_synchronous();
651 }
653 val = (tmp & ~(0xffff << alignment)) |
654 ((val & 0xffff) << alignment);
655 break;
657 case 3:
658 /* will it happen? */
659 printk("vlapic_write with len = 3 !!!\n");
660 domain_crash_synchronous();
661 break;
663 default:
664 printk("Local APIC write with len = %lx, should be 4 instead\n", len);
665 domain_crash_synchronous();
666 break;
667 }
668 }
670 offset &= 0xff0;
672 switch ( offset ) {
673 case APIC_ID: /* Local APIC ID */
674 vlapic->id = ((val) >> 24) & VAPIC_ID_MASK;
675 break;
677 case APIC_TASKPRI:
678 vlapic->task_priority = val & 0xff;
679 vlapic_update_ppr(vlapic);
680 break;
682 case APIC_EOI:
683 vlapic_EOI_set(vlapic);
684 break;
686 case APIC_LDR:
687 vlapic->logical_dest = val & VAPIC_LDR_MASK;
688 break;
690 case APIC_DFR:
691 vlapic->dest_format = val ;
692 break;
694 case APIC_SPIV:
695 vlapic->spurious_vec = val & 0x1ff;
696 if ( !(vlapic->spurious_vec & 0x100) )
697 {
698 int i;
699 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
700 vlapic->lvt[i] |= 0x10000;
701 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
702 }
703 else
704 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
705 break;
707 case APIC_ESR:
708 vlapic->err_write_count = !vlapic->err_write_count;
709 if ( !vlapic->err_write_count )
710 vlapic->err_status = 0;
711 break;
713 case APIC_ICR:
714 /* No delay here, so we always clear the pending bit*/
715 vlapic->icr_low = val & ~(1 << 12);
716 vlapic_ipi(vlapic);
717 break;
719 case APIC_ICR2:
720 vlapic->icr_high = val & 0xff000000;
721 break;
723 case APIC_LVTT: // LVT Timer Reg
724 case APIC_LVTTHMR: // LVT Thermal Monitor
725 case APIC_LVTPC: // LVT Performance Counter
726 case APIC_LVT0: // LVT LINT0 Reg
727 case APIC_LVT1: // LVT Lint1 Reg
728 case APIC_LVTERR: // LVT Error Reg
729 {
730 int vt = (offset - APIC_LVTT) >> 4;
732 vlapic->lvt[vt] = val & vlapic_lvt_mask[vt];
733 if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
734 vlapic->lvt[vt] |= VLAPIC_LVT_BIT_MASK;
736 /* On hardware, when write vector less than 0x20 will error */
737 vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic->lvt[vt]),
738 vlapic_lvt_vector(vlapic, vt));
740 if ( !vlapic->vcpu_id && (offset == APIC_LVT0) )
741 {
742 if ( (vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_DELIMOD)
743 == 0x700 )
744 {
745 if ( vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_MASK )
746 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
747 else
748 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
749 }
750 else
751 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
752 }
754 }
755 break;
757 case APIC_TMICT:
758 {
759 s_time_t now = NOW(), offset;
761 if ( vlapic_timer_active(vlapic) )
762 stop_timer(&vlapic->vlapic_timer);
764 vlapic->timer_initial_count = val;
765 vlapic->timer_current_count = val;
766 vlapic->timer_current_update = now;
768 offset = APIC_BUS_CYCLE_NS *
769 vlapic->timer_divide_count *
770 vlapic->timer_initial_count;
772 set_timer(&vlapic->vlapic_timer, now + offset);
774 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
775 "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
776 "timer initial count 0x%x, offset 0x%016"PRIx64", "
777 "expire @ 0x%016"PRIx64".",
778 APIC_BUS_CYCLE_NS, now, vlapic->timer_initial_count,
779 offset, now + offset);
780 }
781 break;
783 case APIC_TDCR:
784 {
785 unsigned int tmp1, tmp2;
787 tmp1 = val & 0xf;
788 tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
789 vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
791 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
792 vlapic->timer_divide_count);
793 }
794 break;
796 default:
797 printk("Local APIC Write to read-only register\n");
798 break;
799 }
800 }
802 static int vlapic_range(struct vcpu *v, unsigned long addr)
803 {
804 struct vlapic *vlapic = VLAPIC(v);
806 if ( vlapic_global_enabled(vlapic) &&
807 (addr >= vlapic->base_address) &&
808 (addr <= vlapic->base_address + VLOCAL_APIC_MEM_LENGTH) )
809 return 1;
811 return 0;
812 }
814 struct hvm_mmio_handler vlapic_mmio_handler = {
815 .check_handler = vlapic_range,
816 .read_handler = vlapic_read,
817 .write_handler = vlapic_write
818 };
820 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
821 {
822 /* When apic disabled */
823 if ( vlapic == NULL )
824 return;
826 if ( vlapic->vcpu_id )
827 value &= ~MSR_IA32_APICBASE_BSP;
829 vlapic->apic_base_msr = value;
830 vlapic->base_address = vlapic_get_base_address(vlapic);
832 if ( !(value & 0x800) )
833 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
835 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
836 "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
837 vlapic->apic_base_msr, vlapic->base_address);
838 }
840 static inline int vlapic_get_init_id(struct vcpu *v)
841 {
842 return v->vcpu_id;
843 }
845 void vlapic_timer_fn(void *data)
846 {
847 struct vlapic *vlapic = data;
848 struct vcpu *v;
849 uint32_t timer_vector;
850 s_time_t now;
852 if ( unlikely(!vlapic_enabled(vlapic) ||
853 !vlapic_lvt_timer_enabled(vlapic)) )
854 return;
856 v = vlapic->vcpu;
857 timer_vector = vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER);
858 now = NOW();
860 vlapic->timer_current_update = now;
862 if ( test_and_set_bit(timer_vector, &vlapic->irr[0]) )
863 vlapic->intr_pending_count[timer_vector]++;
865 if ( vlapic_lvt_timer_period(vlapic) )
866 {
867 s_time_t offset;
869 vlapic->timer_current_count = vlapic->timer_initial_count;
871 offset = APIC_BUS_CYCLE_NS *
872 vlapic->timer_divide_count *
873 vlapic->timer_initial_count;
874 set_timer(&vlapic->vlapic_timer, now + offset);
875 }
876 else
877 vlapic->timer_current_count = 0;
879 #if 0
880 if ( test_bit(_VCPUF_running, &v->vcpu_flags) )
881 {
882 /* TODO: add guest time handling here */
883 }
884 #endif
886 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
887 "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
888 "timer initial count 0x%x, timer current count 0x%x.",
889 now, vlapic->vlapic_timer.expires,
890 vlapic->timer_initial_count,
891 vlapic->timer_current_count);
892 }
894 #if 0
895 static int
896 vlapic_check_direct_intr(struct vcpu *v, int * mode)
897 {
898 struct vlapic *vlapic = VLAPIC(v);
899 int type;
901 type = fls(vlapic->direct_intr.deliver_mode) - 1;
902 if ( type == -1 )
903 return -1;
905 *mode = type;
906 return 0;
907 }
908 #endif
910 int vlapic_accept_pic_intr(struct vcpu *v)
911 {
912 struct vlapic *vlapic = VLAPIC(v);
914 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
915 }
917 int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
918 {
919 struct vlapic *vlapic = VLAPIC(v);
921 if ( vlapic && vlapic_enabled(vlapic) )
922 {
923 int highest_irr = vlapic_find_highest_irr(vlapic);
925 if ( highest_irr != -1 &&
926 ( (highest_irr & 0xF0) > vlapic->processor_priority ) )
927 {
928 if ( highest_irr < 0x10 )
929 {
930 uint32_t err_vector;
932 vlapic->err_status |= 0x20;
933 err_vector = vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR);
935 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
936 "Sending an illegal vector 0x%x.", highest_irr);
938 set_bit(err_vector, &vlapic->irr[0]);
939 highest_irr = err_vector;
940 }
942 *mode = VLAPIC_DELIV_MODE_FIXED;
943 return highest_irr;
944 }
945 }
946 return -1;
947 }
949 int cpu_has_apic_interrupt(struct vcpu* v)
950 {
951 struct vlapic *vlapic = VLAPIC(v);
953 if (vlapic && vlapic_enabled(vlapic)) {
954 int highest_irr = vlapic_find_highest_irr(vlapic);
956 if ( highest_irr != -1 &&
957 ( (highest_irr & 0xF0) > vlapic->processor_priority ) ) {
958 return 1;
959 }
960 }
961 return 0;
962 }
964 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
965 {
966 struct vlapic *vlapic = VLAPIC(v);
968 if ( unlikely(vlapic == NULL) )
969 return;
971 switch ( deliver_mode ) {
972 case VLAPIC_DELIV_MODE_FIXED:
973 case VLAPIC_DELIV_MODE_LPRI:
974 set_bit(vector, &vlapic->isr[0]);
975 clear_bit(vector, &vlapic->irr[0]);
976 vlapic_update_ppr(vlapic);
978 if ( vector == vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER) )
979 {
980 vlapic->intr_pending_count[vector]--;
981 if ( vlapic->intr_pending_count[vector] > 0 )
982 test_and_set_bit(vector, &vlapic->irr[0]);
983 }
984 break;
986 /*XXX deal with these later */
987 case VLAPIC_DELIV_MODE_RESERVED:
988 printk("Ignore deliver mode 3 in vlapic_post_injection\n");
989 break;
991 case VLAPIC_DELIV_MODE_SMI:
992 case VLAPIC_DELIV_MODE_NMI:
993 case VLAPIC_DELIV_MODE_INIT:
994 case VLAPIC_DELIV_MODE_STARTUP:
995 vlapic->direct_intr.deliver_mode &= ~(1 << deliver_mode);
996 break;
998 default:
999 printk("<vlapic_post_injection> invalid deliver mode\n");
1000 break;
1004 static int vlapic_reset(struct vlapic *vlapic)
1006 struct vcpu *v;
1007 int apic_id, i;
1009 ASSERT( vlapic != NULL );
1011 v = vlapic->vcpu;
1013 ASSERT( v != NULL );
1015 apic_id = v->vcpu_id;
1017 vlapic->domain = v->domain;
1019 vlapic->id = apic_id;
1021 vlapic->vcpu_id = v->vcpu_id;
1023 vlapic->version = VLAPIC_VERSION;
1025 vlapic->apic_base_msr = VLAPIC_BASE_MSR_INIT_VALUE;
1027 if ( apic_id == 0 )
1028 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
1030 vlapic->base_address = vlapic_get_base_address(vlapic);
1032 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
1033 vlapic->lvt[i] = VLAPIC_LVT_BIT_MASK;
1035 vlapic->dest_format = 0xffffffffU;
1037 vlapic->spurious_vec = 0xff;
1039 hvm_vioapic_add_lapic(vlapic, v);
1041 init_timer(&vlapic->vlapic_timer,
1042 vlapic_timer_fn, vlapic, v->processor);
1044 #ifdef VLAPIC_NO_BIOS
1045 /*
1046 * XXX According to mp sepcific, BIOS will enable LVT0/1,
1047 * remove it after BIOS enabled
1048 */
1049 if ( !v->vcpu_id )
1051 vlapic->lvt[VLAPIC_LVT_LINT0] = 0x700;
1052 vlapic->lvt[VLAPIC_LVT_LINT1] = 0x500;
1053 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
1055 #endif
1057 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
1058 "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
1059 "base_address=0x%0lx.",
1060 v, vlapic->id, vlapic->apic_base_msr, vlapic->base_address);
1062 return 1;
1065 int vlapic_init(struct vcpu *v)
1067 struct vlapic *vlapic = NULL;
1069 ASSERT( v != NULL );
1071 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
1073 vlapic = xmalloc_bytes(sizeof(struct vlapic));
1074 if ( vlapic == NULL )
1076 printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
1077 return -ENOMEM;
1080 memset(vlapic, 0, sizeof(struct vlapic));
1082 VLAPIC(v) = vlapic;
1084 vlapic->vcpu = v;
1086 vlapic_reset(vlapic);
1088 return 0;