ia64/xen-unstable

view xen/arch/x86/hvm/vlapic.c @ 10908:a6cb8ba24a91

[HVM] Place all APIC registers into one page in native format.
With this change we can re-use code at include/asm-x86/apicdef.h,
making the code much cleaner. Also it help for future enhancement.

This patch does not change any logic except the change to
CONTROL_REG_ACCESS_NUM, which should be 0xf for CR8 access.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com
author kfraser@localhost.localdomain
date Wed Aug 02 10:07:03 2006 +0100 (2006-08-02)
parents 637b6d60e792
children b33c08de3d98
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 /* LVTT */
47 LVT_MASK | APIC_LVT_TIMER_PERIODIC,
48 /* LVTTHMR */
49 LVT_MASK | APIC_MODE_MASK,
50 /* LVTPC */
51 LVT_MASK | APIC_MODE_MASK,
52 /* LVT0-1 */
53 LINT_MASK, LINT_MASK,
54 /* LVTERR */
55 LVT_MASK
56 };
58 int hvm_apic_support(struct domain *d)
59 {
60 return d->arch.hvm_domain.apic_enabled;
61 }
63 int vlapic_find_highest_irr(struct vlapic *vlapic)
64 {
65 int result;
67 result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_IRR),
68 MAX_VECTOR);
70 ASSERT( result == -1 || result > 16);
72 return result;
73 }
75 s_time_t get_apictime_scheduled(struct vcpu *v)
76 {
77 struct vlapic *vlapic = VLAPIC(v);
79 if ( !hvm_apic_support(v->domain) ||
80 !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
81 return -1;
83 return vlapic->vlapic_timer.expires;
84 }
86 int vlapic_find_highest_isr(struct vlapic *vlapic)
87 {
88 int result;
90 result = find_highest_bit((unsigned long *)(vlapic->regs + APIC_ISR),
91 MAX_VECTOR);
93 ASSERT( result == -1 || result > 16);
95 return result;
96 }
98 uint32_t vlapic_update_ppr(struct vlapic *vlapic)
99 {
100 uint32_t tpr, isrv, ppr;
101 int isr;
103 tpr = vlapic_get_reg(vlapic, APIC_TASKPRI);
105 isr = vlapic_find_highest_isr(vlapic);
107 if ( isr != -1 )
108 isrv = (isr >> 4) & 0xf; /* ditto */
109 else
110 isrv = 0;
112 if ( (tpr >> 4) >= isrv )
113 ppr = tpr & 0xff;
114 else
115 ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */
117 vlapic_set_reg(vlapic, APIC_PROCPRI, ppr);
119 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
120 "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x.",
121 vlapic, ppr, isr, isrv);
123 return ppr;
124 }
126 /* This only for fixed delivery mode */
127 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
128 int short_hand, int dest, int dest_mode,
129 int delivery_mode)
130 {
131 int result = 0;
132 struct vlapic *target = VLAPIC(v);
134 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest 0x%x, "
135 "dest_mode 0x%x, short_hand 0x%x, delivery_mode 0x%x.",
136 target, source, dest, dest_mode, short_hand, delivery_mode);
138 if ( unlikely(target == NULL) &&
139 ((delivery_mode != APIC_DM_INIT) &&
140 (delivery_mode != APIC_DM_STARTUP) &&
141 (delivery_mode != APIC_DM_NMI)) )
142 {
143 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "uninitialized target vcpu %p, "
144 "delivery_mode 0x%x, dest 0x%x.\n", v, delivery_mode, dest);
145 return result;
146 }
148 switch ( short_hand ) {
149 case APIC_DEST_NOSHORT: /* no shorthand */
150 if ( !dest_mode ) /* Physical */
151 {
152 result = ( ((target != NULL) ?
153 GET_APIC_ID(vlapic_get_reg(target, APIC_ID)):
154 v->vcpu_id)) == dest;
155 }
156 else /* Logical */
157 {
158 uint32_t ldr = vlapic_get_reg(target, APIC_LDR);
160 if ( target == NULL )
161 break;
162 /* Flat mode */
163 if ( vlapic_get_reg(target, APIC_DFR) == APIC_DFR_FLAT)
164 {
165 result = GET_APIC_LOGICAL_ID(ldr) & dest;
166 }
167 else
168 {
169 if ( (delivery_mode == APIC_DM_LOWEST) &&
170 (dest == 0xff) )
171 {
172 /* What shall we do now? */
173 printk("Broadcast IPI with lowest priority "
174 "delivery mode\n");
175 domain_crash_synchronous();
176 }
177 result = (GET_APIC_LOGICAL_ID(ldr) == (dest & 0xf)) ?
178 (GET_APIC_LOGICAL_ID(ldr) >> 4) & (dest >> 4) : 0;
179 }
180 }
181 break;
183 case APIC_DEST_SELF:
184 if ( target == source )
185 result = 1;
186 break;
188 case APIC_DEST_ALLINC:
189 result = 1;
190 break;
192 case APIC_DEST_ALLBUT:
193 if ( target != source )
194 result = 1;
195 break;
197 default:
198 break;
199 }
201 return result;
202 }
204 /*
205 * Add a pending IRQ into lapic.
206 * Return 1 if successfully added and 0 if discarded.
207 */
208 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
209 int vector, int level, int trig_mode)
210 {
211 int result = 0;
212 struct vlapic *vlapic = VLAPIC(v);
214 switch ( delivery_mode ) {
215 case APIC_DM_FIXED:
216 case APIC_DM_LOWEST:
217 /* FIXME add logic for vcpu on reset */
218 if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
219 break;
221 if ( test_and_set_bit(vector, vlapic->regs + APIC_IRR) )
222 {
223 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
224 "level trig mode repeatedly for vector %d\n", vector);
225 break;
226 }
228 if ( level )
229 {
230 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
231 "level trig mode for vector %d\n", vector);
232 set_bit(vector, vlapic->regs + APIC_TMR);
233 }
234 evtchn_set_pending(v, iopacket_port(v));
236 result = 1;
237 break;
239 case APIC_DM_REMRD:
240 printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
241 break;
243 case APIC_DM_SMI:
244 case APIC_DM_NMI:
245 /* Fixme */
246 printk("TODO: for guest SMI/NMI\n");
247 break;
249 case APIC_DM_INIT:
250 if ( level && !(trig_mode & APIC_INT_ASSERT) ) //Deassert
251 printk("This hvm_vlapic is for P4, no work for De-assert init\n");
252 else
253 {
254 /* FIXME How to check the situation after vcpu reset? */
255 if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
256 {
257 printk("Reset hvm vcpu not supported yet\n");
258 domain_crash_synchronous();
259 }
260 v->arch.hvm_vcpu.init_sipi_sipi_state =
261 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
262 result = 1;
263 }
264 break;
266 case APIC_DM_STARTUP:
267 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
268 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
269 break;
271 v->arch.hvm_vcpu.init_sipi_sipi_state =
272 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
274 if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
275 {
276 printk("SIPI for initialized vcpu vcpuid %x\n", v->vcpu_id);
277 domain_crash_synchronous();
278 }
280 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
281 result = 0;
282 break;
284 default:
285 printk("TODO: not support interrupt type %x\n", delivery_mode);
286 domain_crash_synchronous();
287 break;
288 }
290 return result;
291 }
292 /*
293 This function is used by both ioapic and local APIC
294 The bitmap is for vcpu_id
295 */
296 struct vlapic* apic_round_robin(struct domain *d,
297 uint8_t dest_mode,
298 uint8_t vector,
299 uint32_t bitmap)
300 {
301 int next, old;
302 struct vlapic* target = NULL;
304 if ( dest_mode == 0 ) //Physical mode
305 {
306 printk("<apic_round_robin> lowest priority for physical mode.\n");
307 return NULL;
308 }
310 if ( !bitmap )
311 {
312 printk("<apic_round_robin> no bit set in bitmap.\n");
313 return NULL;
314 }
316 spin_lock(&d->arch.hvm_domain.round_robin_lock);
318 old = next = d->arch.hvm_domain.round_info[vector];
320 /* the vcpu array is arranged according to vcpu_id */
321 do
322 {
323 next++;
324 if ( !d->vcpu[next] ||
325 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) ||
326 next == MAX_VIRT_CPUS )
327 next = 0;
329 if ( test_bit(next, &bitmap) )
330 {
331 target = d->vcpu[next]->arch.hvm_vcpu.vlapic;
333 if ( target == NULL || !vlapic_enabled(target) )
334 {
335 printk("warning: targe round robin local apic disabled\n");
336 /* XXX should we domain crash?? Or should we return NULL */
337 }
338 break;
339 }
340 } while ( next != old );
342 d->arch.hvm_domain.round_info[vector] = next;
343 spin_unlock(&d->arch.hvm_domain.round_robin_lock);
345 return target;
346 }
348 void vlapic_EOI_set(struct vlapic *vlapic)
349 {
350 int vector = vlapic_find_highest_isr(vlapic);
352 /* Not every write EOI will has correpsoning ISR,
353 one example is when Kernel check timer on setup_IO_APIC */
354 if ( vector == -1 )
355 return ;
357 clear_bit(vector, vlapic->regs + APIC_ISR);
358 vlapic_update_ppr(vlapic);
360 if ( test_and_clear_bit(vector, vlapic->regs + APIC_TMR) )
361 ioapic_update_EOI(vlapic->domain, vector);
362 }
364 static int vlapic_check_vector(struct vlapic *vlapic,
365 uint32_t dm, uint32_t vector)
366 {
367 if ( (dm == APIC_DM_FIXED) && (vector < 16) )
368 {
369 vlapic->err_status |= 0x40;
370 vlapic_accept_irq(vlapic->vcpu, APIC_DM_FIXED,
371 vlapic_lvt_vector(vlapic, APIC_LVTERR), 0, 0);
372 printk("<vlapic_check_vector>: check failed "
373 " dm %x vector %x\n", dm, vector);
374 return 0;
375 }
376 return 1;
377 }
379 void vlapic_ipi(struct vlapic *vlapic)
380 {
381 uint32_t icr_low = vlapic_get_reg(vlapic, APIC_ICR);
382 uint32_t icr_high = vlapic_get_reg(vlapic, APIC_ICR2);
384 unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
385 unsigned int short_hand = icr_low & APIC_SHORT_MASK;
386 unsigned int trig_mode = icr_low & APIC_INT_ASSERT;
387 unsigned int level = icr_low & APIC_INT_LEVELTRIG;
388 unsigned int dest_mode = icr_low & APIC_DEST_MASK;
389 unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
390 unsigned int vector = icr_low & APIC_VECTOR_MASK;
392 struct vlapic *target;
393 struct vcpu *v = NULL;
394 uint32_t lpr_map;
396 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr_high 0x%x, icr_low 0x%x, "
397 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
398 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x.",
399 icr_high, icr_low, short_hand, dest,
400 trig_mode, level, dest_mode, delivery_mode, vector);
402 for_each_vcpu ( vlapic->domain, v )
403 {
404 if ( vlapic_match_dest(v, vlapic, short_hand,
405 dest, dest_mode, delivery_mode) )
406 {
407 if ( delivery_mode == APIC_DM_LOWEST)
408 set_bit(v->vcpu_id, &lpr_map);
409 else
410 vlapic_accept_irq(v, delivery_mode,
411 vector, level, trig_mode);
412 }
413 }
415 if ( delivery_mode == APIC_DM_LOWEST)
416 {
417 v = vlapic->vcpu;
418 target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
420 if ( target )
421 vlapic_accept_irq(target->vcpu, delivery_mode,
422 vector, level, trig_mode);
423 }
424 }
426 static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
427 {
428 uint32_t counter_passed;
429 s_time_t passed, now = NOW();
430 uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT);
432 ASSERT(vlapic != NULL);
434 if ( unlikely(now <= vlapic->timer_last_update) )
435 {
436 passed = ~0x0LL - vlapic->timer_last_update + now;
437 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed.");
438 }
439 else
440 passed = now - vlapic->timer_last_update;
442 counter_passed = passed /
443 (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
445 tmcct -= counter_passed;
447 if ( tmcct <= 0 )
448 {
449 if ( unlikely(!vlapic_lvtt_period(vlapic)) )
450 {
451 tmcct = 0;
452 // FIXME: should we add interrupt here?
453 }
454 else
455 {
456 do {
457 tmcct += vlapic_get_reg(vlapic, APIC_TMICT);
458 } while ( tmcct < 0 );
459 }
460 }
462 vlapic->timer_last_update = now;
463 vlapic_set_reg(vlapic, APIC_TMCCT, tmcct);
465 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
466 "timer initial count 0x%x, timer current count 0x%x, "
467 "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.",
468 vlapic_get_reg(vlapic, APIC_TMICT),
469 vlapic_get_reg(vlapic, APIC_TMCCT),
470 vlapic->timer_last_update, now, counter_passed);
472 return tmcct;
473 }
475 static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
476 unsigned int len, unsigned int *result)
477 {
478 ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR);
480 *result = 0;
482 switch ( offset ) {
483 case APIC_ARBPRI:
484 printk("access local APIC ARBPRI register which is for P6\n");
485 break;
487 case APIC_TMCCT: //Timer CCR
488 *result = vlapic_get_tmcct(vlapic);
489 break;
491 default:
492 *result = vlapic_get_reg(vlapic, offset);
493 break;
494 }
495 }
497 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
498 unsigned long len)
499 {
500 unsigned int alignment;
501 unsigned int tmp;
502 unsigned long result;
503 struct vlapic *vlapic = VLAPIC(v);
504 unsigned int offset = address - vlapic->base_address;
506 if ( offset > APIC_TDCR)
507 return 0;
509 /* some bugs on kernel cause read this with byte*/
510 if ( len != 4 )
511 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
512 "read with len=0x%lx, should be 4 instead.\n",
513 len);
515 alignment = offset & 0x3;
517 vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
518 switch ( len ) {
519 case 1:
520 result = *((unsigned char *)&tmp + alignment);
521 break;
523 case 2:
524 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
525 break;
527 case 4:
528 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
529 break;
531 default:
532 printk("Local APIC read with len=0x%lx, should be 4 instead.\n", len);
533 domain_crash_synchronous();
534 break;
535 }
537 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "offset 0x%x with length 0x%lx, "
538 "and the result is 0x%lx.", offset, len, result);
540 return result;
541 }
543 static void vlapic_write(struct vcpu *v, unsigned long address,
544 unsigned long len, unsigned long val)
545 {
546 struct vlapic *vlapic = VLAPIC(v);
547 unsigned int offset = address - vlapic->base_address;
549 if ( offset != 0xb0 )
550 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
551 "offset 0x%x with length 0x%lx, and value is 0x%lx.",
552 offset, len, val);
554 /*
555 * According to IA 32 Manual, all resgiters should be accessed with
556 * 32 bits alignment.
557 */
558 if ( len != 4 )
559 {
560 unsigned int tmp;
561 unsigned char alignment;
563 /* Some kernel do will access with byte/word alignment*/
564 printk("Notice: Local APIC write with len = %lx\n",len);
565 alignment = offset & 0x3;
566 tmp = vlapic_read(v, offset & ~0x3, 4);
567 switch ( len ) {
568 case 1:
569 /* XXX the saddr is a tmp variable from caller, so should be ok
570 But we should still change the following ref to val to
571 local variable later */
572 val = (tmp & ~(0xff << alignment)) |
573 ((val & 0xff) << alignment);
574 break;
576 case 2:
577 if ( alignment != 0x0 && alignment != 0x2 )
578 {
579 printk("alignment error for vlapic with len == 2\n");
580 domain_crash_synchronous();
581 }
583 val = (tmp & ~(0xffff << alignment)) |
584 ((val & 0xffff) << alignment);
585 break;
587 case 3:
588 /* will it happen? */
589 printk("vlapic_write with len = 3 !!!\n");
590 domain_crash_synchronous();
591 break;
593 default:
594 printk("Local APIC write with len = %lx, should be 4 instead\n", len);
595 domain_crash_synchronous();
596 break;
597 }
598 }
600 offset &= 0xff0;
602 switch ( offset ) {
603 case APIC_ID: /* Local APIC ID */
604 vlapic_set_reg(vlapic, APIC_ID, val);
605 break;
607 case APIC_TASKPRI:
608 vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
609 vlapic_update_ppr(vlapic);
610 break;
612 case APIC_EOI:
613 vlapic_EOI_set(vlapic);
614 break;
616 case APIC_LDR:
617 vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK);
618 break;
620 case APIC_DFR:
621 vlapic_set_reg(vlapic, APIC_DFR, val);
622 break;
624 case APIC_SPIV:
625 vlapic_set_reg(vlapic, APIC_SPIV, val & 0x1ff);
627 if ( !( val & APIC_SPIV_APIC_ENABLED) )
628 {
629 int i;
630 uint32_t lvt_val;
632 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
634 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
635 {
636 lvt_val = vlapic_get_reg(vlapic, APIC_LVT1 + 0x10 * i);
637 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
638 lvt_val | APIC_LVT_MASKED);
639 }
641 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
642 == APIC_DM_EXTINT )
643 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
644 }
645 else
646 {
647 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
648 if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
649 == APIC_DM_EXTINT )
650 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
651 }
652 break;
654 case APIC_ESR:
655 vlapic->err_write_count = !vlapic->err_write_count;
656 if ( !vlapic->err_write_count )
657 vlapic->err_status = 0;
658 break;
660 case APIC_ICR:
661 /* No delay here, so we always clear the pending bit*/
662 vlapic_set_reg(vlapic, APIC_ICR, val & ~(1 << 12));
663 vlapic_ipi(vlapic);
664 break;
666 case APIC_ICR2:
667 vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000);
668 break;
670 case APIC_LVTT: // LVT Timer Reg
671 case APIC_LVTTHMR: // LVT Thermal Monitor
672 case APIC_LVTPC: // LVT Performance Counter
673 case APIC_LVT0: // LVT LINT0 Reg
674 case APIC_LVT1: // LVT Lint1 Reg
675 case APIC_LVTERR: // LVT Error Reg
676 {
677 if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
678 val |= APIC_LVT_MASKED;
680 val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
682 vlapic_set_reg(vlapic, offset, val);
684 /* On hardware, when write vector less than 0x20 will error */
685 if ( !(val & APIC_LVT_MASKED) )
686 vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic, offset),
687 vlapic_lvt_vector(vlapic, offset));
689 if ( !vlapic->vcpu_id && (offset == APIC_LVT0) )
690 {
691 if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
692 if ( val & APIC_LVT_MASKED)
693 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
694 else
695 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
696 else
697 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
698 }
700 }
701 break;
703 case APIC_TMICT:
704 {
705 s_time_t now = NOW(), offset;
707 stop_timer(&vlapic->vlapic_timer);
709 vlapic_set_reg(vlapic, APIC_TMICT, val);
710 vlapic_set_reg(vlapic, APIC_TMCCT, val);
711 vlapic->timer_last_update = now;
713 offset = APIC_BUS_CYCLE_NS *
714 vlapic->timer_divide_count * val;
716 set_timer(&vlapic->vlapic_timer, now + offset);
718 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
719 "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
720 "timer initial count 0x%x, offset 0x%016"PRIx64", "
721 "expire @ 0x%016"PRIx64".",
722 APIC_BUS_CYCLE_NS, now,
723 vlapic_get_reg(vlapic, APIC_TMICT),
724 offset, now + offset);
725 }
726 break;
728 case APIC_TDCR:
729 {
730 unsigned int tmp1, tmp2;
732 tmp1 = val & 0xf;
733 tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
734 vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
736 vlapic_set_reg(vlapic, APIC_TDCR, val);
738 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
739 vlapic->timer_divide_count);
740 }
741 break;
743 default:
744 printk("Local APIC Write to read-only register\n");
745 break;
746 }
747 }
749 static int vlapic_range(struct vcpu *v, unsigned long addr)
750 {
751 struct vlapic *vlapic = VLAPIC(v);
753 if ( vlapic_global_enabled(vlapic) &&
754 (addr >= vlapic->base_address) &&
755 (addr <= vlapic->base_address + VLOCAL_APIC_MEM_LENGTH) )
756 return 1;
758 return 0;
759 }
761 struct hvm_mmio_handler vlapic_mmio_handler = {
762 .check_handler = vlapic_range,
763 .read_handler = vlapic_read,
764 .write_handler = vlapic_write
765 };
767 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
768 {
769 /* When apic disabled */
770 if ( vlapic == NULL )
771 return;
773 if ( vlapic->vcpu_id )
774 value &= ~MSR_IA32_APICBASE_BSP;
776 vlapic->apic_base_msr = value;
777 vlapic->base_address = vlapic->apic_base_msr &
778 MSR_IA32_APICBASE_BASE;
780 /* with FSB delivery interrupt, we can restart APIC functionality */
781 if ( !(value & MSR_IA32_APICBASE_ENABLE) )
782 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
783 else
784 clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
786 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
787 "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
788 vlapic->apic_base_msr, vlapic->base_address);
789 }
791 void vlapic_timer_fn(void *data)
792 {
793 struct vlapic *vlapic = data;
794 struct vcpu *v;
795 uint32_t timer_vector;
796 s_time_t now;
798 if ( unlikely(!vlapic_enabled(vlapic) ||
799 !vlapic_lvt_enabled(vlapic, APIC_LVTT)) )
800 return;
802 v = vlapic->vcpu;
803 timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT);
804 now = NOW();
806 vlapic->timer_last_update = now;
808 if ( test_and_set_bit(timer_vector, vlapic->regs + APIC_IRR ))
809 vlapic->intr_pending_count[timer_vector]++;
811 if ( vlapic_lvtt_period(vlapic) )
812 {
813 s_time_t offset;
814 uint32_t tmict = vlapic_get_reg(vlapic, APIC_TMICT);
816 vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
818 offset = APIC_BUS_CYCLE_NS *
819 vlapic->timer_divide_count * tmict;
821 set_timer(&vlapic->vlapic_timer, now + offset);
822 }
823 else
824 vlapic_set_reg(vlapic, APIC_TMCCT, 0);
826 #if 0
827 if ( test_bit(_VCPUF_running, &v->vcpu_flags) )
828 {
829 /* TODO: add guest time handling here */
830 }
831 #endif
833 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
834 "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
835 "timer initial count 0x%x, timer current count 0x%x.",
836 now, vlapic->vlapic_timer.expires,
837 vlapic_get_reg(vlapic, APIC_TMICT),
838 vlapic_get_reg(vlapic, APIC_TMCCT));
839 }
841 #if 0
842 static int
843 vlapic_check_direct_intr(struct vcpu *v, int * mode)
844 {
845 struct vlapic *vlapic = VLAPIC(v);
846 int type;
848 type = fls(vlapic->direct_intr.deliver_mode) - 1;
849 if ( type == -1 )
850 return -1;
852 *mode = type;
853 return 0;
854 }
855 #endif
857 int vlapic_accept_pic_intr(struct vcpu *v)
858 {
859 struct vlapic *vlapic = VLAPIC(v);
861 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
862 }
864 int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
865 {
866 struct vlapic *vlapic = VLAPIC(v);
868 if ( vlapic && vlapic_enabled(vlapic) )
869 {
870 int highest_irr = vlapic_find_highest_irr(vlapic);
872 if ( highest_irr != -1 &&
873 ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) )
874 {
875 if ( highest_irr < 0x10 )
876 {
877 uint32_t err_vector;
879 vlapic->err_status |= 0x20;
880 err_vector = vlapic_lvt_vector(vlapic, APIC_LVTERR);
882 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
883 "Sending an illegal vector 0x%x.", highest_irr);
885 set_bit(err_vector, vlapic->regs + APIC_IRR);
886 highest_irr = err_vector;
887 }
889 *mode = APIC_DM_FIXED;
890 return highest_irr;
891 }
892 }
893 return -1;
894 }
896 int cpu_has_apic_interrupt(struct vcpu* v)
897 {
898 struct vlapic *vlapic = VLAPIC(v);
900 if (vlapic && vlapic_enabled(vlapic)) {
901 int highest_irr = vlapic_find_highest_irr(vlapic);
903 if ( highest_irr != -1 &&
904 ( (highest_irr & 0xF0) > vlapic_get_reg(vlapic, APIC_PROCPRI) ) ) {
905 return 1;
906 }
907 }
908 return 0;
909 }
911 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
912 {
913 struct vlapic *vlapic = VLAPIC(v);
915 if ( unlikely(vlapic == NULL) )
916 return;
918 switch ( deliver_mode ) {
919 case APIC_DM_FIXED:
920 case APIC_DM_LOWEST:
921 set_bit(vector, vlapic->regs + APIC_ISR);
922 clear_bit(vector, vlapic->regs + APIC_IRR);
923 vlapic_update_ppr(vlapic);
925 if ( vector == vlapic_lvt_vector(vlapic, APIC_LVTT) )
926 {
927 vlapic->intr_pending_count[vector]--;
928 if ( vlapic->intr_pending_count[vector] > 0 )
929 test_and_set_bit(vector, vlapic->regs + APIC_IRR);
930 }
931 break;
933 /*XXX deal with these later */
934 case APIC_DM_REMRD:
935 printk("Ignore deliver mode 3 in vlapic_post_injection\n");
936 break;
938 case APIC_DM_SMI:
939 case APIC_DM_NMI:
940 case APIC_DM_INIT:
941 case APIC_DM_STARTUP:
942 vlapic->direct_intr.deliver_mode &= deliver_mode;
943 break;
945 default:
946 printk("<vlapic_post_injection> invalid deliver mode\n");
947 break;
948 }
949 }
951 static int vlapic_reset(struct vlapic *vlapic)
952 {
953 struct vcpu *v;
954 int i;
956 ASSERT( vlapic != NULL );
958 v = vlapic->vcpu;
960 ASSERT( v != NULL );
962 vlapic->domain = v->domain;
964 vlapic->vcpu_id = v->vcpu_id;
966 vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
968 vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
970 for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
971 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
973 vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
975 vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
977 vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
979 if ( v->vcpu_id == 0 )
980 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
982 vlapic->base_address = vlapic->apic_base_msr &
983 MSR_IA32_APICBASE_BASE;
985 hvm_vioapic_add_lapic(vlapic, v);
987 init_timer(&vlapic->vlapic_timer,
988 vlapic_timer_fn, vlapic, v->processor);
990 #ifdef VLAPIC_NO_BIOS
991 /*
992 * XXX According to mp sepcific, BIOS will enable LVT0/1,
993 * remove it after BIOS enabled
994 */
995 if ( !v->vcpu_id )
996 {
997 vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
998 vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
999 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
1001 #endif
1003 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
1004 "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
1005 "base_address=0x%0lx.",
1006 v, GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
1007 vlapic->apic_base_msr, vlapic->base_address);
1009 return 1;
1012 int vlapic_init(struct vcpu *v)
1014 struct vlapic *vlapic = NULL;
1016 ASSERT( v != NULL );
1018 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
1020 vlapic = xmalloc_bytes(sizeof(struct vlapic));
1021 if ( vlapic == NULL )
1023 printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
1024 return -ENOMEM;
1027 memset(vlapic, 0, sizeof(struct vlapic));
1029 vlapic->regs_page = alloc_domheap_page(NULL);
1030 if ( vlapic->regs_page == NULL )
1032 printk("malloc vlapic regs error for vcpu %x\n", v->vcpu_id);
1033 xfree(vlapic);
1034 return -ENOMEM;
1037 vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
1039 memset(vlapic->regs, 0, PAGE_SIZE);
1041 VLAPIC(v) = vlapic;
1043 vlapic->vcpu = v;
1045 vlapic_reset(vlapic);
1047 return 0;