ia64/xen-unstable

view xen/arch/x86/hvm/vlapic.c @ 9016:cf1c1bb9f6d2

Bring up AP of VMX domain.
1) add INIT-SIPI-SIPI IPI sequence handling code to HVM virtual lapic
code.
2) add an new interface init_ap_context to hvm_funcs, and implement the
VMX side.
3) add a hvm generic function hvm_bringup_ap, which in turn calls
init_ap_context.

Signed-off-by: Xin Li <xin.b.li@intel.com>
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Feb 24 17:32:58 2006 +0100 (2006-02-24)
parents b5bb9920bf48
children 503c4d8454e5
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 unsigned int get_apic_bus_scale(void);
42 static unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] =
43 {
44 0x310ff, 0x117ff, 0x117ff, 0x1f7ff, 0x1f7ff, 0x117ff
45 };
47 int vlapic_find_highest_irr(struct vlapic *vlapic)
48 {
49 int result;
51 result = find_highest_bit((uint32_t *)&vlapic->irr[0], INTR_LEN_32);
53 if (result != -1 && result < 16) {
54 printk("VLAPIC: irr on reserved bits %d\n ", result);
55 domain_crash_synchronous();
56 }
58 return result;
59 }
61 int hvm_apic_support(struct domain *d)
62 {
63 return d->arch.hvm_domain.apic_enabled;
64 }
66 s_time_t get_apictime_scheduled(struct vcpu *v)
67 {
68 struct vlapic *vlapic = VLAPIC(v);
70 if ( !hvm_apic_support(v->domain) || !vlapic_lvt_timer_enabled(vlapic) )
71 return -1;
72 return vlapic->vlapic_timer.expires;
73 }
75 int vlapic_find_highest_isr(struct vlapic *vlapic)
76 {
77 int result;
79 result = find_highest_bit((uint32_t *)&vlapic->isr[0], INTR_LEN_32);
81 if (result != -1 && result < 16) {
82 int i = 0;
83 printk("VLAPIC: isr on reserved bits %d, isr is\n ", result);
84 for (i = 0; i < INTR_LEN_32; i += 2)
85 printk("%d: 0x%08x%08x\n", i, vlapic->isr[i], vlapic->isr[i+1]);
86 return -1;
87 }
89 return result;
90 }
92 uint32_t vlapic_update_ppr(struct vlapic *vlapic)
93 {
94 uint32_t tpr, isrv, ppr;
95 int isr;
97 tpr = (vlapic->task_priority >> 4) & 0xf; /* we want 7:4 */
99 isr = vlapic_find_highest_isr(vlapic);
100 if (isr != -1)
101 isrv = (isr >> 4) & 0xf; /* ditto */
102 else
103 isrv = 0;
105 if (tpr >= isrv)
106 ppr = vlapic->task_priority & 0xff;
107 else
108 ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */
110 vlapic->processor_priority = ppr;
112 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
113 "vlapic_update_ppr: vlapic %p ppr %x isr %x isrv %x",
114 vlapic, ppr, isr, isrv);
116 return ppr;
117 }
119 /* This only for fixed delivery mode */
120 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
121 int short_hand, int dest, int dest_mode,
122 int delivery_mode)
123 {
124 int result = 0;
125 struct vlapic *target = VLAPIC(v);
127 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_match_dest: "
128 "target %p source %p dest %x dest_mode %x short_hand %x "
129 "delivery_mode %x",
130 target, source, dest, dest_mode, short_hand, delivery_mode);
132 if ( unlikely(!target) &&
133 ( (delivery_mode != VLAPIC_DELIV_MODE_INIT) &&
134 (delivery_mode != VLAPIC_DELIV_MODE_STARTUP) &&
135 (delivery_mode != VLAPIC_DELIV_MODE_NMI) )) {
136 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_match_dest "
137 "uninitialized target v %p delivery_mode %x dest %x\n",
138 v, delivery_mode, dest);
139 return result;
140 }
142 switch (short_hand) {
143 case VLAPIC_NO_SHORTHAND:
144 if (!dest_mode) { /* Physical */
145 result = ((target ? target->id : v->vcpu_id ) == dest);
146 } else { /* Logical */
147 if (!target)
148 break;
149 if (((target->dest_format >> 28) & 0xf) == 0xf) { /* Flat mode */
150 result = (target->logical_dest >> 24) & dest;
151 } else {
152 if ((delivery_mode == VLAPIC_DELIV_MODE_LPRI) &&
153 (dest == 0xff)) {
154 /* What shall we do now? */
155 printk("Broadcast IPI with lowest priority "
156 "delivery mode\n");
157 domain_crash_synchronous();
158 }
159 result = (target->logical_dest == (dest & 0xf)) ?
160 ((target->logical_dest >> 4) & (dest >> 4)) : 0;
161 }
162 }
163 break;
165 case VLAPIC_SHORTHAND_SELF:
166 if (target == source)
167 result = 1;
168 break;
170 case VLAPIC_SHORTHAND_INCLUDE_SELF:
171 result = 1;
172 break;
174 case VLAPIC_SHORTHAND_EXCLUDE_SELF:
175 if (target != source)
176 result = 1;
177 break;
179 default:
180 break;
181 }
183 return result;
184 }
186 /*
187 * Add a pending IRQ into lapic.
188 * Return 1 if successfully added and 0 if discarded.
189 */
190 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
191 int vector, int level, int trig_mode)
192 {
193 int result = 0;
194 struct vlapic *vlapic = VLAPIC(v);
196 switch (delivery_mode) {
197 case VLAPIC_DELIV_MODE_FIXED:
198 case VLAPIC_DELIV_MODE_LPRI:
199 /* FIXME add logic for vcpu on reset */
200 if (unlikely(!vlapic || !vlapic_enabled(vlapic)))
201 return result;
203 if (test_and_set_bit(vector, &vlapic->irr[0])) {
204 printk("<vlapic_accept_irq>"
205 "level trig mode repeatedly for vector %d\n", vector);
206 result = 0;
207 } else {
208 if (level) {
209 printk("<vlapic_accept_irq> level trig mode for vector %d\n", vector);
210 set_bit(vector, &vlapic->tmr[0]);
211 }
212 }
213 evtchn_set_pending(vlapic->vcpu, iopacket_port(vlapic->vcpu));
214 result = 1;
215 break;
217 case VLAPIC_DELIV_MODE_RESERVED:
218 printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
219 break;
221 case VLAPIC_DELIV_MODE_SMI:
222 case VLAPIC_DELIV_MODE_NMI:
223 /* Fixme */
224 printk("TODO: for guest SMI/NMI\n");
225 break;
227 case VLAPIC_DELIV_MODE_INIT:
228 if ( !level && trig_mode == 1 ) { //Deassert
229 printk("This hvm_vlapic is for P4, no work for De-assert init\n");
230 } else {
231 /* FIXME How to check the situation after vcpu reset? */
232 if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) ) {
233 printk("Reset hvm vcpu not supported yet\n");
234 domain_crash_synchronous();
235 }
236 v->arch.hvm_vcpu.init_sipi_sipi_state =
237 HVM_VCPU_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
238 result = 1;
239 }
240 break;
242 case VLAPIC_DELIV_MODE_STARTUP:
243 if ( v->arch.hvm_vcpu.init_sipi_sipi_state ==
244 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM )
245 break;
247 v->arch.hvm_vcpu.init_sipi_sipi_state =
248 HVM_VCPU_INIT_SIPI_SIPI_STATE_NORM;
250 if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) {
251 printk("SIPI for initialized vcpu vcpuid %x\n", v->vcpu_id);
252 domain_crash_synchronous();
253 }
255 if ( hvm_bringup_ap(v->vcpu_id, vector) != 0 )
256 result = 0;
257 break;
259 default:
260 printk("TODO: not support interrup type %x\n", delivery_mode);
261 domain_crash_synchronous();
262 break;
263 }
265 return result;
266 }
267 /*
268 This function is used by both ioapic and local APIC
269 The bitmap is for vcpu_id
270 */
271 struct vlapic* apic_round_robin(struct domain *d,
272 uint8_t dest_mode,
273 uint8_t vector,
274 uint32_t bitmap)
275 {
276 int next, old;
277 struct vlapic* target = NULL;
279 if (dest_mode == 0) { //Physical mode
280 printk("<apic_round_robin> lowest priority for physical mode\n");
281 return NULL;
282 }
284 if (!bitmap) {
285 printk("<apic_round_robin> no bit on bitmap\n");
286 return NULL;
287 }
289 spin_lock(&d->arch.hvm_domain.round_robin_lock);
291 old = next = d->arch.hvm_domain.round_info[vector];
293 do {
294 /* the vcpu array is arranged according to vcpu_id */
295 if (test_bit(next, &bitmap)) {
296 target = d->vcpu[next]->arch.hvm_vcpu.vlapic;
298 if (!target || !vlapic_enabled(target)) {
299 printk("warning: targe round robin local apic disabled\n");
300 /* XXX should we domain crash?? Or should we return NULL */
301 }
302 break;
303 }
305 next ++;
306 if (!d->vcpu[next] ||
307 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) ||
308 next == MAX_VIRT_CPUS)
309 next = 0;
310 }while(next != old);
312 d->arch.hvm_domain.round_info[vector] = next;
313 spin_unlock(&d->arch.hvm_domain.round_robin_lock);
314 return target;
315 }
317 void
318 vlapic_EOI_set(struct vlapic *vlapic)
319 {
320 int vector = vlapic_find_highest_isr(vlapic);
322 /* Not every write EOI will has correpsoning ISR,
323 one example is when Kernel check timer on setup_IO_APIC */
324 if (vector == -1) {
325 return ;
326 }
328 vlapic_clear_isr(vlapic, vector);
329 vlapic_update_ppr(vlapic);
331 if (test_and_clear_bit(vector, &vlapic->tmr[0]))
332 ioapic_update_EOI(vlapic->domain, vector);
333 }
335 int vlapic_check_vector(struct vlapic *vlapic,
336 unsigned char dm, int vector)
337 {
338 if ((dm == VLAPIC_DELIV_MODE_FIXED) && (vector < 16)) {
339 vlapic->err_status |= 0x40;
340 vlapic_accept_irq(vlapic->vcpu, VLAPIC_DELIV_MODE_FIXED,
341 vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), 0, 0);
342 printk("<vlapic_check_vector>: check fail\n");
343 return 0;
344 }
345 return 1;
346 }
349 void vlapic_ipi(struct vlapic *vlapic)
350 {
351 unsigned int dest = (vlapic->icr_high >> 24) & 0xff;
352 unsigned int short_hand = (vlapic->icr_low >> 18) & 3;
353 unsigned int trig_mode = (vlapic->icr_low >> 15) & 1;
354 unsigned int level = (vlapic->icr_low >> 14) & 1;
355 unsigned int dest_mode = (vlapic->icr_low >> 11) & 1;
356 unsigned int delivery_mode = (vlapic->icr_low >> 8) & 7;
357 unsigned int vector = (vlapic->icr_low & 0xff);
359 struct vlapic *target;
360 struct vcpu *v = NULL;
361 uint32_t lpr_map;
363 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_ipi: "
364 "icr_high %x icr_low %x "
365 "short_hand %x dest %x trig_mode %x level %x "
366 "dest_mode %x delivery_mode %x vector %x",
367 vlapic->icr_high, vlapic->icr_low,
368 short_hand, dest, trig_mode, level, dest_mode,
369 delivery_mode, vector);
371 for_each_vcpu ( vlapic->domain, v ) {
372 if (vlapic_match_dest(v, vlapic, short_hand,
373 dest, dest_mode, delivery_mode)) {
374 if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) {
375 set_bit(v->vcpu_id, &lpr_map);
376 } else
377 vlapic_accept_irq(v, delivery_mode,
378 vector, level, trig_mode);
379 }
380 }
382 if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) {
383 v = vlapic->vcpu;
384 target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
386 if (target)
387 vlapic_accept_irq(target->vcpu, delivery_mode,
388 vector, level, trig_mode);
389 }
390 }
392 static void vlapic_begin_timer(struct vlapic *vlapic)
393 {
394 s_time_t cur = NOW(), offset;
396 offset = vlapic->timer_current *
397 (262144 / get_apic_bus_scale()) * vlapic->timer_divide_counter;
398 vlapic->vlapic_timer.expires = cur + offset;
400 set_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires );
402 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_begin_timer: "
403 "bus_scale %x now %08x%08x expire %08x%08x "
404 "offset %08x%08x current %x",
405 get_apic_bus_scale(), (uint32_t)(cur >> 32), (uint32_t)cur,
406 (uint32_t)(vlapic->vlapic_timer.expires >> 32),
407 (uint32_t) vlapic->vlapic_timer.expires,
408 (uint32_t)(offset >> 32), (uint32_t)offset,
409 vlapic->timer_current);
410 }
412 void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
413 unsigned int len, unsigned int *result)
414 {
415 if (len != 4) {
416 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
417 "local apic read with len=%d (should be 4)", len);
418 }
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;
515 break;
517 case APIC_TMCCT: //Timer CCR
518 {
519 uint32_t counter;
520 s_time_t passed, cur = NOW();
522 if (cur <= vlapic->timer_current_update) {
523 passed = ~0x0LL - vlapic->timer_current_update + cur;
524 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,"time elapsed");
525 }else
526 passed = cur - vlapic->timer_current_update;
528 counter = (passed * get_apic_bus_scale()) / (262144* vlapic->timer_divide_counter);
529 if (vlapic->timer_current > counter)
530 *result = vlapic->timer_current - counter;
531 else {
532 if (!vlapic_lvt_timer_period(vlapic))
533 *result = 0;
534 //FIXME should we add interrupt here?
535 else
536 //*result = counter % vlapic->timer_initial;
537 *result = vlapic->timer_initial - (counter - vlapic->timer_current);
538 }
539 vlapic->timer_current = *result;
540 vlapic->timer_current_update = NOW();
542 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
543 "initial %x timer current %x "
544 "update %08x%08x cur %08x%08x offset %d",
545 vlapic->timer_initial, vlapic->timer_current,
546 (uint32_t)(vlapic->timer_current_update >> 32),
547 (uint32_t)vlapic->timer_current_update ,
548 (uint32_t)(cur >> 32), (uint32_t)cur, counter);
549 }
550 break;
552 case APIC_TDCR:
553 *result = vlapic->timer_divconf;
554 break;
556 default:
557 printk("Read local APIC address %x not implemented\n",offset);
558 *result = 0;
559 break;
560 }
561 }
563 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
564 unsigned long len)
565 {
566 unsigned int alignment;
567 unsigned int tmp;
568 unsigned long result;
569 struct vlapic *vlapic = VLAPIC(v);
570 unsigned int offset = address - vlapic->base_address;
572 if ( len != 4) {
573 /* some bugs on kernel cause read this with byte*/
574 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
575 "Local APIC read with len = %lx, should be 4 instead\n",
576 len);
577 }
579 alignment = offset & 0x3;
581 vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
582 switch (len) {
583 case 1:
584 result = *((unsigned char *)&tmp + alignment);
585 break;
587 case 2:
588 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
589 break;
591 case 4:
592 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
593 break;
595 default:
596 printk("Local APIC read with len = %lx, should be 4 instead\n", len);
597 domain_crash_synchronous();
598 break;
599 }
601 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
602 "vlapic_read offset %x with length %lx and the result is %lx",
603 offset, len, result);
604 return result;
605 }
607 static void vlapic_write(struct vcpu *v, unsigned long address,
608 unsigned long len, unsigned long val)
609 {
610 struct vlapic *vlapic = VLAPIC(v);
611 unsigned int offset = address - vlapic->base_address;
613 if (offset != 0xb0)
614 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
615 "vlapic_write offset %x with length %lx source %lx",
616 offset, len, val);
618 /*
619 * According to IA 32 Manual, all resgiters should be accessed with
620 * 32 bits alignment.
621 */
622 if (len != 4) {
623 unsigned int tmp;
624 unsigned char alignment;
626 /* Some kernel do will access with byte/word alignment*/
627 printk("Notice: Local APIC write with len = %lx\n",len);
628 alignment = offset & 0x3;
629 tmp = vlapic_read(v, offset & (~0x3), 4);
630 switch (len) {
631 case 1:
632 /* XXX the saddr is a tmp variable from caller, so should be ok
633 But we should still change the following ref to val to
634 local variable later */
635 val = (tmp & ~(0xff << alignment)) |
636 ((val & 0xff) << alignment);
637 break;
639 case 2:
640 if (alignment != 0x0 && alignment != 0x2) {
641 printk("alignment error for vlapic with len == 2\n");
642 domain_crash_synchronous();
643 }
645 val = (tmp & ~(0xffff << alignment)) |
646 ((val & 0xffff) << alignment);
647 break;
649 case 3:
650 /* will it happen? */
651 printk("vlapic_write with len = 3 !!!\n");
652 domain_crash_synchronous();
653 break;
655 default:
656 printk("Local APIC write with len = %lx, should be 4 instead\n", len);
657 domain_crash_synchronous();
658 break;
659 }
660 }
662 offset &= 0xff0;
664 switch (offset) {
665 case APIC_ID: /* Local APIC ID */
666 vlapic->id = ((val) >> 24) & VAPIC_ID_MASK;
667 break;
669 case APIC_TASKPRI:
670 vlapic->task_priority = val & 0xff;
671 vlapic_update_ppr(vlapic);
672 break;
674 case APIC_EOI:
675 vlapic_EOI_set(vlapic);
676 break;
678 case APIC_LDR:
679 vlapic->logical_dest = val & VAPIC_LDR_MASK;
680 break;
682 case APIC_DFR:
683 vlapic->dest_format = val ;
684 break;
686 case APIC_SPIV:
687 vlapic->spurious_vec = val & 0x1ff;
688 if (!(vlapic->spurious_vec & 0x100)) {
689 int i = 0;
690 for (i = 0; i < VLAPIC_LVT_NUM; i++)
691 vlapic->lvt[i] |= 0x10000;
692 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
693 }
694 else
695 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
696 break;
698 case APIC_ESR:
699 vlapic->err_write_count = !vlapic->err_write_count;
700 if (!vlapic->err_write_count)
701 vlapic->err_status = 0;
702 break;
704 case APIC_ICR:
705 /* No delay here, so we always clear the pending bit*/
706 vlapic->icr_low = val & ~(1 << 12);
707 vlapic_ipi(vlapic);
708 break;
710 case APIC_ICR2:
711 vlapic->icr_high = val & 0xff000000;
712 break;
714 case APIC_LVTT: // LVT Timer Reg
715 case APIC_LVTTHMR: // LVT Thermal Monitor
716 case APIC_LVTPC: // LVT Performance Counter
717 case APIC_LVT0: // LVT LINT0 Reg
718 case APIC_LVT1: // LVT Lint1 Reg
719 case APIC_LVTERR: // LVT Error Reg
720 {
721 int vt = (offset - APIC_LVTT) >> 4;
723 vlapic->lvt[vt] = val & vlapic_lvt_mask[vt];
724 if (vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK)
725 vlapic->lvt[vt] |= VLAPIC_LVT_BIT_MASK;
727 /* On hardware, when write vector less than 0x20 will error */
728 vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic->lvt[vt]),
729 vlapic_lvt_vector(vlapic, vt));
731 if (!vlapic->vcpu_id && (offset == APIC_LVT0)) {
732 if ((vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_DELIMOD)
733 == 0x700) {
734 if (!(vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_MASK)) {
735 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
736 }else
737 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
738 }
739 else
740 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
741 }
743 }
744 break;
746 case APIC_TMICT:
747 if (vlapic_timer_active(vlapic))
748 stop_timer(&(vlapic->vlapic_timer));
750 vlapic->timer_initial = val;
751 vlapic->timer_current = val;
752 vlapic->timer_current_update = NOW();
754 vlapic_begin_timer(vlapic);
756 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "timer_init %x timer_current %x"
757 "timer_current_update %08x%08x",
758 vlapic->timer_initial, vlapic->timer_current,
759 (uint32_t)(vlapic->timer_current_update >> 32),
760 (uint32_t)vlapic->timer_current_update);
761 break;
763 case APIC_TDCR:
764 {
765 //FIXME clean this code
766 unsigned char tmp1,tmp2;
767 tmp1 = (val & 0xf);
768 tmp2 = ((tmp1 & 0x3 )|((tmp1 & 0x8) >>1)) + 1;
769 vlapic->timer_divide_counter = 0x1<<tmp2;
771 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
772 "timer divider is 0x%x",
773 vlapic->timer_divide_counter);
774 }
775 break;
777 default:
778 printk("Local APIC Write to read-only register\n");
779 break;
780 }
781 }
783 static int vlapic_range(struct vcpu *v, unsigned long addr)
784 {
785 struct vlapic *vlapic = VLAPIC(v);
787 if (vlapic_global_enabled(vlapic) &&
788 (addr >= vlapic->base_address) &&
789 (addr <= (vlapic->base_address + VLOCAL_APIC_MEM_LENGTH)))
790 return 1;
792 return 0;
793 }
795 struct hvm_mmio_handler vlapic_mmio_handler = {
796 .check_handler = vlapic_range,
797 .read_handler = vlapic_read,
798 .write_handler = vlapic_write
799 };
801 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
802 {
803 /* When apic disabled */
804 if (!vlapic)
805 return;
807 if (vlapic->vcpu_id)
808 value &= ~MSR_IA32_APICBASE_BSP;
810 vlapic->apic_base_msr = value;
811 vlapic->base_address = vlapic_get_base_address(vlapic);
813 if (!(value & 0x800))
814 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
816 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
817 "apic base msr = 0x%08x%08x,\nbase address = 0x%lx",
818 (uint32_t)(vlapic->apic_base_msr >> 32),
819 (uint32_t)vlapic->apic_base_msr,
820 vlapic->base_address);
821 }
823 static inline int vlapic_get_init_id(struct vcpu *v)
824 {
825 return v->vcpu_id;
826 }
828 void vlapic_timer_fn(void *data)
829 {
830 struct vlapic *vlapic;
832 vlapic = data;
833 if (!vlapic_enabled(vlapic)) return;
835 vlapic->timer_current_update = NOW();
837 if (vlapic_lvt_timer_enabled(vlapic)) {
838 if (!vlapic_irr_status(vlapic,
839 vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER))) {
840 test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER),
841 &vlapic->irr[0]);
842 }
843 else
844 vlapic->intr_pending_count[vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)]++;
845 evtchn_set_pending(vlapic->vcpu, iopacket_port(vlapic->vcpu));
846 }
848 vlapic->timer_current_update = NOW();
849 if (vlapic_lvt_timer_period(vlapic)) {
850 s_time_t offset;
852 vlapic->timer_current = vlapic->timer_initial;
853 offset = vlapic->timer_current * (262144/get_apic_bus_scale()) * vlapic->timer_divide_counter;
854 vlapic->vlapic_timer.expires = NOW() + offset;
855 set_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires);
856 }else {
857 vlapic->timer_current = 0;
858 }
860 HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
861 "vlapic_timer_fn: now: %08x%08x expire %08x%08x init %x current %x",
862 (uint32_t)(NOW() >> 32),(uint32_t)NOW(),
863 (uint32_t)(vlapic->vlapic_timer.expires >> 32),
864 (uint32_t)vlapic->vlapic_timer.expires,
865 vlapic->timer_initial,vlapic->timer_current);
866 }
868 #if 0
869 static int
870 vlapic_check_direct_intr(struct vcpu *v, int * mode)
871 {
872 struct vlapic *vlapic = VLAPIC(v);
873 int type;
875 type = __fls(vlapic->direct_intr.deliver_mode);
876 if (type == -1)
877 return -1;
879 *mode = type;
880 return 0;
881 }
882 #endif
884 int
885 vlapic_accept_pic_intr(struct vcpu *v)
886 {
887 struct vlapic *vlapic = VLAPIC(v);
889 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
890 }
892 int cpu_get_apic_interrupt(struct vcpu* v, int *mode)
893 {
894 struct vlapic *vlapic = VLAPIC(v);
896 if (vlapic && vlapic_enabled(vlapic)) {
897 int highest_irr = vlapic_find_highest_irr(vlapic);
899 if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) {
900 if (highest_irr < 0x10) {
901 vlapic->err_status |= 0x20;
902 /* XXX What will happen if this vector illegal stil */
903 HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
904 "hvm_intr_assist: illegal vector number %x err_status %x",
905 highest_irr, vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR));
907 set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), &vlapic->irr[0]);
908 highest_irr = vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR);
909 }
911 *mode = VLAPIC_DELIV_MODE_FIXED;
912 return highest_irr;
913 }
914 }
915 return -1;
916 }
918 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) {
919 struct vlapic *vlapic = VLAPIC(v);
921 if (!vlapic)
922 return;
924 switch (deliver_mode) {
925 case VLAPIC_DELIV_MODE_FIXED:
926 case VLAPIC_DELIV_MODE_LPRI:
927 vlapic_set_isr(vlapic, vector);
928 vlapic_clear_irr(vlapic, vector);
929 vlapic_update_ppr(vlapic);
931 if (vector == vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)) {
932 vlapic->intr_pending_count[vector]--;
933 if (vlapic->intr_pending_count[vector] > 0)
934 test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER),
935 &vlapic->irr[0]);
936 }
938 break;
939 /*XXX deal with these later */
941 case VLAPIC_DELIV_MODE_RESERVED:
942 printk("Ignore deliver mode 3 in vlapic_post_injection\n");
943 break;
945 case VLAPIC_DELIV_MODE_SMI:
946 case VLAPIC_DELIV_MODE_NMI:
947 case VLAPIC_DELIV_MODE_INIT:
948 case VLAPIC_DELIV_MODE_STARTUP:
949 vlapic->direct_intr.deliver_mode &= ~(1 << deliver_mode);
950 break;
952 default:
953 printk("<vlapic_post_injection> error deliver mode\n");
954 break;
955 }
956 }
958 static int vlapic_reset(struct vlapic *vlapic)
959 {
960 struct vcpu *v;
961 int apic_id, i;
963 ASSERT( vlapic != NULL );
965 v = vlapic->vcpu;
967 ASSERT( v != NULL );
969 apic_id = v->vcpu_id;
971 vlapic->domain = v->domain;
973 vlapic->id = apic_id;
975 vlapic->vcpu_id = v->vcpu_id;
977 vlapic->version = VLAPIC_VERSION;
979 vlapic->apic_base_msr = VLAPIC_BASE_MSR_INIT_VALUE;
981 if (apic_id == 0)
982 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
984 vlapic->base_address = vlapic_get_base_address(vlapic);
986 for (i = 0; i < VLAPIC_LVT_NUM; i++)
987 vlapic->lvt[i] = VLAPIC_LVT_BIT_MASK;
989 vlapic->dest_format = 0xffffffffU;
991 vlapic->spurious_vec = 0xff;
993 hvm_vioapic_add_lapic(vlapic, v);
995 init_timer(&vlapic->vlapic_timer,
996 vlapic_timer_fn, vlapic, v->processor);
998 #ifdef VLAPIC_NO_BIOS
999 /*
1000 * XXX According to mp sepcific, BIOS will enable LVT0/1,
1001 * remove it after BIOS enabled
1002 */
1003 if (!v->vcpu_id) {
1004 vlapic->lvt[VLAPIC_LVT_LINT0] = 0x700;
1005 vlapic->lvt[VLAPIC_LVT_LINT1] = 0x500;
1006 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
1008 #endif
1010 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_reset: "
1011 "vcpu=%p id=%d vlapic_apic_base_msr=%08x%08x "
1012 "vlapic_base_address=%0lx",
1013 v, vlapic->id, (uint32_t)(vlapic->apic_base_msr >> 32),
1014 (uint32_t)vlapic->apic_base_msr, vlapic->base_address);
1016 return 1;
1019 int vlapic_init(struct vcpu *v)
1021 struct vlapic *vlapic = NULL;
1023 ASSERT( v != NULL );
1025 HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
1027 vlapic = xmalloc_bytes(sizeof(struct vlapic));
1028 if (!vlapic) {
1029 printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
1030 return -ENOMEM;
1033 memset(vlapic, 0, sizeof(struct vlapic));
1035 VLAPIC(v) = vlapic;
1037 vlapic->vcpu = v;
1039 vlapic_reset(vlapic);
1041 return 0;