ia64/xen-unstable

view xen/arch/x86/vmx_vlapic.c @ 7815:00aa8e4609e2

Properly declare ioapic_update_EOI().

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Nov 15 11:28:33 2005 +0100 (2005-11-15)
parents eaee11008e68
children 412995d28a07
line source
1 /*
2 * vmx_vlapic.c: virtualize LAPIC for VMX vcpus.
3 * Copyright (c) 2004, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
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/vmx.h>
29 #include <asm/vmx_platform.h>
30 #include <asm/vmx_vlapic.h>
31 #include <asm/vmx_vioapic.h>
32 #include <xen/lib.h>
33 #include <xen/sched.h>
34 #include <asm/current.h>
35 #include <public/io/ioreq.h>
37 #ifdef CONFIG_VMX
39 /* XXX remove this definition after GFW enabled */
40 #define VLAPIC_NO_BIOS
42 extern unsigned int get_apic_bus_scale(void);
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((uint32_t *)&vlapic->irr[0], INTR_LEN_32);
55 if (result != -1 && result < 16) {
56 printk("VLAPIC: irr on reserved bits %d\n ", result);
57 domain_crash_synchronous();
58 }
60 return result;
61 }
63 int vmx_apic_support(struct domain *d)
64 {
65 return d->arch.vmx_platform.lapic_enable;
66 }
68 s_time_t get_apictime_scheduled(struct vcpu *v)
69 {
70 struct vlapic *vlapic = VLAPIC(v);
72 if ( !vmx_apic_support(v->domain) || !vlapic_lvt_timer_enabled(vlapic) )
73 return -1;
74 return vlapic->vlapic_timer.expires;
75 }
77 int vlapic_find_highest_isr(struct vlapic *vlapic)
78 {
79 int result;
81 result = find_highest_bit((uint32_t *)&vlapic->isr[0], INTR_LEN_32);
83 if (result != -1 && result < 16) {
84 int i = 0;
85 printk("VLAPIC: isr on reserved bits %d, isr is\n ", result);
86 for (i = 0; i < INTR_LEN_32; i += 2)
87 printk("%d: 0x%08x%08x\n", i, vlapic->isr[i], vlapic->isr[i+1]);
88 return -1;
89 }
91 return result;
92 }
94 uint32_t vlapic_update_ppr(struct vlapic *vlapic)
95 {
96 uint32_t tpr, isrv, ppr;
97 int isr;
99 tpr = (vlapic->task_priority >> 4) & 0xf; /* we want 7:4 */
101 isr = vlapic_find_highest_isr(vlapic);
102 if (isr != -1)
103 isrv = (isr >> 4) & 0xf; /* ditto */
104 else
105 isrv = 0;
107 if (tpr >= isrv)
108 ppr = vlapic->task_priority & 0xff;
109 else
110 ppr = isrv << 4; /* low 4 bits of PPR have to be cleared */
112 vlapic->processor_priority = ppr;
114 VMX_DBG_LOG(DBG_LEVEL_VLAPIC_INTERRUPT,
115 "vlapic_update_ppr: vlapic %p ppr %x isr %x isrv %x",
116 vlapic, ppr, isr, isrv);
118 return ppr;
119 }
121 /* This only for fixed delivery mode */
122 static int vlapic_match_dest(struct vcpu *v, struct vlapic *source,
123 int short_hand, int dest, int dest_mode,
124 int delivery_mode)
125 {
126 int result = 0;
127 struct vlapic *target = VLAPIC(v);
129 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_match_dest: "
130 "target %p source %p dest %x dest_mode %x short_hand %x "
131 "delivery_mode %x",
132 target, source, dest, dest_mode, short_hand, delivery_mode);
134 if ( unlikely(!target) &&
135 ( (delivery_mode != VLAPIC_DELIV_MODE_INIT) &&
136 (delivery_mode != VLAPIC_DELIV_MODE_STARTUP) &&
137 (delivery_mode != VLAPIC_DELIV_MODE_NMI) )) {
138 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_match_dest "
139 "uninitialized target v %p delivery_mode %x dest %x\n",
140 v, delivery_mode, dest);
141 return result;
142 }
144 switch (short_hand) {
145 case VLAPIC_NO_SHORTHAND:
146 if (!dest_mode) { /* Physical */
147 result = ((target ? target->id : v->vcpu_id ) == dest);
148 } else { /* Logical */
149 if (!target)
150 break;
151 if (((target->dest_format >> 28) & 0xf) == 0xf) { /* Flat mode */
152 result = (target->logical_dest >> 24) & dest;
153 } else {
154 if ((delivery_mode == VLAPIC_DELIV_MODE_LPRI) &&
155 (dest == 0xff)) {
156 /* What shall we do now? */
157 printk("Broadcast IPI with lowest priority "
158 "delivery mode\n");
159 domain_crash_synchronous();
160 }
161 result = (target->logical_dest == (dest & 0xf)) ?
162 ((target->logical_dest >> 4) & (dest >> 4)) : 0;
163 }
164 }
165 break;
167 case VLAPIC_SHORTHAND_SELF:
168 if (target == source)
169 result = 1;
170 break;
172 case VLAPIC_SHORTHAND_INCLUDE_SELF:
173 result = 1;
174 break;
176 case VLAPIC_SHORTHAND_EXCLUDE_SELF:
177 if (target != source)
178 result = 1;
179 break;
181 default:
182 break;
183 }
185 return result;
186 }
188 /*
189 * Add a pending IRQ into lapic.
190 * Return 1 if successfully added and 0 if discarded.
191 */
192 static int vlapic_accept_irq(struct vcpu *v, int delivery_mode,
193 int vector, int level, int trig_mode)
194 {
195 int result = 0;
196 struct vlapic *vlapic = VLAPIC(v);
198 switch (delivery_mode) {
199 case VLAPIC_DELIV_MODE_FIXED:
200 case VLAPIC_DELIV_MODE_LPRI:
201 /* FIXME add logic for vcpu on reset */
202 if (unlikely(!vlapic || !vlapic_enabled(vlapic)))
203 return result;
205 if (test_and_set_bit(vector, &vlapic->irr[0])) {
206 printk("<vlapic_accept_irq>"
207 "level trig mode repeatedly for vector %d\n", vector);
208 result = 0;
209 } else {
210 if (level) {
211 printk("<vlapic_accept_irq> level trig mode for vector %d\n", vector);
212 set_bit(vector, &vlapic->tmr[0]);
213 }
214 }
215 evtchn_set_pending(vlapic->vcpu, iopacket_port(vlapic->domain));
216 result = 1;
217 break;
219 case VLAPIC_DELIV_MODE_RESERVED:
220 printk("Ignore deliver mode 3 in vlapic_accept_irq\n");
221 break;
223 case VLAPIC_DELIV_MODE_SMI:
224 case VLAPIC_DELIV_MODE_NMI:
225 /* Fixme */
226 printk("TODO: for guest SMI/NMI\n");
227 break;
229 case VLAPIC_DELIV_MODE_INIT:
230 if (!level && trig_mode == 1) { //Deassert
231 printk("This vmx_vlapic is for P4, no work for De-assert init\n");
232 } else {
233 /* FIXME How to check the situation after vcpu reset? */
234 vlapic->init_sipi_sipi_state = VLAPIC_INIT_SIPI_SIPI_STATE_WAIT_SIPI;
235 if (vlapic->vcpu) {
236 vcpu_pause(vlapic->vcpu);
237 }
238 }
239 break;
241 case VLAPIC_DELIV_MODE_STARTUP:
242 if (vlapic->init_sipi_sipi_state != VLAPIC_INIT_SIPI_SIPI_STATE_WAIT_SIPI)
243 break;
244 vlapic->init_sipi_sipi_state = VLAPIC_INIT_SIPI_SIPI_STATE_NORM;
245 if (!vlapic->vcpu) {
246 /* XXX Call vmx_bringup_ap here */
247 result = 0;
248 }else{
249 //vmx_vcpu_reset(vlapic->vcpu);
250 }
251 break;
253 default:
254 printk("TODO: not support interrup type %x\n", delivery_mode);
255 domain_crash_synchronous();
256 break;
257 }
259 return result;
260 }
261 /*
262 This function is used by both ioapic and local APIC
263 The bitmap is for vcpu_id
264 */
265 struct vlapic* apic_round_robin(struct domain *d,
266 uint8_t dest_mode,
267 uint8_t vector,
268 uint32_t bitmap)
269 {
270 int next, old;
271 struct vlapic* target = NULL;
273 if (dest_mode == 0) { //Physical mode
274 printk("<apic_round_robin> lowest priority for physical mode\n");
275 return NULL;
276 }
278 if (!bitmap) {
279 printk("<apic_round_robin> no bit on bitmap\n");
280 return NULL;
281 }
283 spin_lock(&d->arch.vmx_platform.round_robin_lock);
285 old = next = d->arch.vmx_platform.round_info[vector];
287 do {
288 /* the vcpu array is arranged according to vcpu_id */
289 if (test_bit(next, &bitmap)) {
290 target = d->vcpu[next]->arch.arch_vmx.vlapic;
292 if (!target || !vlapic_enabled(target)) {
293 printk("warning: targe round robin local apic disabled\n");
294 /* XXX should we domain crash?? Or should we return NULL */
295 }
296 break;
297 }
299 next ++;
300 if (!d->vcpu[next] ||
301 !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) ||
302 next == MAX_VIRT_CPUS)
303 next = 0;
304 }while(next != old);
306 d->arch.vmx_platform.round_info[vector] = next;
307 spin_unlock(&d->arch.vmx_platform.round_robin_lock);
308 return target;
309 }
311 void
312 vlapic_EOI_set(struct vlapic *vlapic)
313 {
314 int vector = vlapic_find_highest_isr(vlapic);
316 /* Not every write EOI will has correpsoning ISR,
317 one example is when Kernel check timer on setup_IO_APIC */
318 if (vector == -1) {
319 return ;
320 }
322 vlapic_clear_isr(vlapic, vector);
323 vlapic_update_ppr(vlapic);
325 if (test_and_clear_bit(vector, &vlapic->tmr[0]))
326 ioapic_update_EOI(vlapic->domain, vector);
327 }
329 int vlapic_check_vector(struct vlapic *vlapic,
330 unsigned char dm, int vector)
331 {
332 if ((dm == VLAPIC_DELIV_MODE_FIXED) && (vector < 16)) {
333 vlapic->err_status |= 0x40;
334 vlapic_accept_irq(vlapic->vcpu, VLAPIC_DELIV_MODE_FIXED,
335 vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), 0, 0);
336 printk("<vlapic_check_vector>: check fail\n");
337 return 0;
338 }
339 return 1;
340 }
343 void vlapic_ipi(struct vlapic *vlapic)
344 {
345 unsigned int dest = (vlapic->icr_high >> 24) & 0xff;
346 unsigned int short_hand = (vlapic->icr_low >> 18) & 3;
347 unsigned int trig_mode = (vlapic->icr_low >> 15) & 1;
348 unsigned int level = (vlapic->icr_low >> 14) & 1;
349 unsigned int dest_mode = (vlapic->icr_low >> 11) & 1;
350 unsigned int delivery_mode = (vlapic->icr_low >> 8) & 7;
351 unsigned int vector = (vlapic->icr_low & 0xff);
353 struct vlapic *target;
354 struct vcpu *v = NULL;
355 uint32_t lpr_map;
357 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_ipi: "
358 "icr_high %x icr_low %x "
359 "short_hand %x dest %x trig_mode %x level %x "
360 "dest_mode %x delivery_mode %x vector %x",
361 vlapic->icr_high, vlapic->icr_low,
362 short_hand, dest, trig_mode, level, dest_mode,
363 delivery_mode, vector);
365 for_each_vcpu ( vlapic->domain, v ) {
366 if (vlapic_match_dest(v, vlapic, short_hand,
367 dest, dest_mode, delivery_mode)) {
368 if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) {
369 set_bit(v->vcpu_id, &lpr_map);
370 } else
371 vlapic_accept_irq(v, delivery_mode,
372 vector, level, trig_mode);
373 }
374 }
376 if (delivery_mode == VLAPIC_DELIV_MODE_LPRI) {
377 v = vlapic->vcpu;
378 target = apic_round_robin(v->domain, dest_mode, vector, lpr_map);
380 if (target)
381 vlapic_accept_irq(target->vcpu, delivery_mode,
382 vector, level, trig_mode);
383 }
384 }
386 static void vlapic_begin_timer(struct vlapic *vlapic)
387 {
388 s_time_t cur = NOW(), offset;
390 offset = vlapic->timer_current *
391 (262144 / get_apic_bus_scale()) * vlapic->timer_divide_counter;
392 vlapic->vlapic_timer.expires = cur + offset;
394 set_ac_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires );
396 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_begin_timer: "
397 "bus_scale %x now %08x%08x expire %08x%08x "
398 "offset %08x%08x current %x",
399 get_apic_bus_scale(), (uint32_t)(cur >> 32), (uint32_t)cur,
400 (uint32_t)(vlapic->vlapic_timer.expires >> 32),
401 (uint32_t) vlapic->vlapic_timer.expires,
402 (uint32_t)(offset >> 32), (uint32_t)offset,
403 vlapic->timer_current);
404 }
406 void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
407 unsigned int len, unsigned int *result)
408 {
409 if (len != 4) {
410 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
411 "local apic read with len=%d (should be 4)", len);
412 }
414 *result = 0;
416 switch (offset) {
417 case APIC_ID:
418 *result = (vlapic->id) << 24;
419 break;
421 case APIC_LVR:
422 *result = vlapic->version;
423 break;
425 case APIC_TASKPRI:
426 *result = vlapic->task_priority;
427 break;
429 case APIC_ARBPRI:
430 printk("Access local APIC ARBPRI register which is for P6\n");
431 break;
433 case APIC_PROCPRI:
434 *result = vlapic->processor_priority;
435 break;
437 case APIC_EOI: /* EOI is write only */
438 break;
440 case APIC_LDR:
441 *result = vlapic->logical_dest;
442 break;
444 case APIC_DFR:
445 *result = vlapic->dest_format;
446 break;
448 case APIC_SPIV:
449 *result = vlapic->spurious_vec;
450 break;
452 case APIC_ISR:
453 case 0x110:
454 case 0x120:
455 case 0x130:
456 case 0x140:
457 case 0x150:
458 case 0x160:
459 case 0x170:
460 *result = vlapic->isr[(offset - APIC_ISR) >> 4];
461 break;
463 case APIC_TMR:
464 case 0x190:
465 case 0x1a0:
466 case 0x1b0:
467 case 0x1c0:
468 case 0x1d0:
469 case 0x1e0:
470 case 0x1f0:
471 *result = vlapic->tmr[(offset - APIC_TMR) >> 4];
472 break;
474 case APIC_IRR:
475 case 0x210:
476 case 0x220:
477 case 0x230:
478 case 0x240:
479 case 0x250:
480 case 0x260:
481 case 0x270:
482 *result = vlapic->irr[(offset - APIC_IRR) >> 4];
483 break;
485 case APIC_ESR:
486 if (vlapic->err_write_count)
487 *result = vlapic->err_status;
488 break;
490 case APIC_ICR:
491 *result = vlapic->icr_low;
492 break;
494 case APIC_ICR2:
495 *result = vlapic->icr_high;
496 break;
498 case APIC_LVTT: /* LVT Timer Reg */
499 case APIC_LVTTHMR: /* LVT Thermal Monitor */
500 case APIC_LVTPC: /* LVT Performance Counter */
501 case APIC_LVT0: /* LVT LINT0 Reg */
502 case APIC_LVT1: /* LVT Lint1 Reg */
503 case APIC_LVTERR: /* LVT Error Reg */
504 *result = vlapic->lvt[(offset - APIC_LVTT) >> 4];
505 break;
507 case APIC_TMICT:
508 *result = vlapic->timer_initial;
509 break;
511 case APIC_TMCCT: //Timer CCR
512 {
513 uint32_t counter;
514 s_time_t passed, cur = NOW();
516 if (cur <= vlapic->timer_current_update) {
517 passed = ~0x0LL - vlapic->timer_current_update + cur;
518 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,"time elapsed");
519 }else
520 passed = cur - vlapic->timer_current_update;
522 counter = (passed * get_apic_bus_scale()) / (262144* vlapic->timer_divide_counter);
523 if (vlapic->timer_current > counter)
524 *result = vlapic->timer_current - counter;
525 else {
526 if (!vlapic_lvt_timer_period(vlapic))
527 *result = 0;
528 //FIXME should we add interrupt here?
529 else
530 //*result = counter % vlapic->timer_initial;
531 *result = vlapic->timer_initial - (counter - vlapic->timer_current);
532 }
533 vlapic->timer_current = *result;
534 vlapic->timer_current_update = NOW();
536 VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
537 "initial %x timer current %x "
538 "update %08x%08x cur %08x%08x offset %d",
539 vlapic->timer_initial, vlapic->timer_current,
540 (uint32_t)(vlapic->timer_current_update >> 32),
541 (uint32_t)vlapic->timer_current_update ,
542 (uint32_t)(cur >> 32), (uint32_t)cur, counter);
543 }
544 break;
546 case APIC_TDCR:
547 *result = vlapic->timer_divconf;
548 break;
550 default:
551 printk("Read local APIC address %x not implemented\n",offset);
552 *result = 0;
553 break;
554 }
555 }
557 static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
558 unsigned long len)
559 {
560 unsigned int alignment;
561 unsigned int tmp;
562 unsigned long result;
563 struct vlapic *vlapic = VLAPIC(v);
564 unsigned int offset = address - vlapic->base_address;
566 if ( len != 4) {
567 /* some bugs on kernel cause read this with byte*/
568 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
569 "Local APIC read with len = %lx, should be 4 instead\n",
570 len);
571 }
573 alignment = offset & 0x3;
575 vlapic_read_aligned(vlapic, offset & ~0x3, 4, &tmp);
576 switch (len) {
577 case 1:
578 result = *((unsigned char *)&tmp + alignment);
579 break;
581 case 2:
582 result = *(unsigned short *)((unsigned char *)&tmp + alignment);
583 break;
585 case 4:
586 result = *(unsigned int *)((unsigned char *)&tmp + alignment);
587 break;
589 default:
590 printk("Local APIC read with len = %lx, should be 4 instead\n", len);
591 domain_crash_synchronous();
592 break;
593 }
595 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
596 "vlapic_read offset %x with length %lx and the result is %lx",
597 offset, len, result);
598 return result;
599 }
601 static void vlapic_write(struct vcpu *v, unsigned long address,
602 unsigned long len, unsigned long val)
603 {
604 struct vlapic *vlapic = VLAPIC(v);
605 unsigned int offset = address - vlapic->base_address;
607 if (offset != 0xb0)
608 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
609 "vlapic_write offset %x with length %lx source %lx",
610 offset, len, val);
612 /*
613 * According to IA 32 Manual, all resgiters should be accessed with
614 * 32 bits alignment.
615 */
616 if (len != 4) {
617 unsigned int tmp;
618 unsigned char alignment;
620 /* Some kernel do will access with byte/word alignment*/
621 printk("Notice: Local APIC write with len = %lx\n",len);
622 alignment = offset & 0x3;
623 tmp = vlapic_read(v, offset & (~0x3), 4);
624 switch (len) {
625 case 1:
626 /* XXX the saddr is a tmp variable from caller, so should be ok
627 But we should still change the following ref to val to
628 local variable later */
629 val = (tmp & ~(0xff << alignment)) |
630 ((val & 0xff) << alignment);
631 break;
633 case 2:
634 if (alignment != 0x0 && alignment != 0x2) {
635 printk("alignment error for vlapic with len == 2\n");
636 domain_crash_synchronous();
637 }
639 val = (tmp & ~(0xffff << alignment)) |
640 ((val & 0xffff) << alignment);
641 break;
643 case 3:
644 /* will it happen? */
645 printk("vlapic_write with len = 3 !!!\n");
646 domain_crash_synchronous();
647 break;
649 default:
650 printk("Local APIC write with len = %lx, should be 4 instead\n", len);
651 domain_crash_synchronous();
652 break;
653 }
654 }
656 offset &= 0xff0;
658 switch (offset) {
659 case APIC_ID: /* Local APIC ID */
660 vlapic->id = ((val) >> 24) & VAPIC_ID_MASK;
661 break;
663 case APIC_TASKPRI:
664 vlapic->task_priority = val & 0xff;
665 vlapic_update_ppr(vlapic);
666 break;
668 case APIC_EOI:
669 vlapic_EOI_set(vlapic);
670 break;
672 case APIC_LDR:
673 vlapic->logical_dest = val & VAPIC_LDR_MASK;
674 break;
676 case APIC_DFR:
677 vlapic->dest_format = val ;
678 break;
680 case APIC_SPIV:
681 vlapic->spurious_vec = val & 0x1ff;
682 if (!(vlapic->spurious_vec & 0x100)) {
683 int i = 0;
684 for (i = 0; i < VLAPIC_LVT_NUM; i++)
685 vlapic->lvt[i] |= 0x10000;
686 vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
687 }
688 else
689 vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
690 break;
692 case APIC_ESR:
693 vlapic->err_write_count = !vlapic->err_write_count;
694 if (!vlapic->err_write_count)
695 vlapic->err_status = 0;
696 break;
698 case APIC_ICR:
699 /* No delay here, so we always clear the pending bit*/
700 vlapic->icr_low = val & ~(1 << 12);
701 vlapic_ipi(vlapic);
702 break;
704 case APIC_ICR2:
705 vlapic->icr_high = val & 0xff000000;
706 break;
708 case APIC_LVTT: // LVT Timer Reg
709 case APIC_LVTTHMR: // LVT Thermal Monitor
710 case APIC_LVTPC: // LVT Performance Counter
711 case APIC_LVT0: // LVT LINT0 Reg
712 case APIC_LVT1: // LVT Lint1 Reg
713 case APIC_LVTERR: // LVT Error Reg
714 {
715 int vt = (offset - APIC_LVTT) >> 4;
717 vlapic->lvt[vt] = val & vlapic_lvt_mask[vt];
718 if (vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK)
719 vlapic->lvt[vt] |= VLAPIC_LVT_BIT_MASK;
721 /* On hardware, when write vector less than 0x20 will error */
722 vlapic_check_vector(vlapic, vlapic_lvt_dm(vlapic->lvt[vt]),
723 vlapic_lvt_vector(vlapic, vt));
725 if (!vlapic->vcpu_id && (offset == APIC_LVT0)) {
726 if ((vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_DELIMOD)
727 == 0x700) {
728 if (!(vlapic->lvt[VLAPIC_LVT_LINT0] & VLAPIC_LVT_BIT_MASK)) {
729 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
730 }else
731 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
732 }
733 else
734 clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
735 }
737 }
738 break;
740 case APIC_TMICT:
741 if (vlapic_timer_active(vlapic))
742 rem_ac_timer(&(vlapic->vlapic_timer));
744 vlapic->timer_initial = val;
745 vlapic->timer_current = val;
746 vlapic->timer_current_update = NOW();
748 vlapic_begin_timer(vlapic);
750 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "timer_init %x timer_current %x"
751 "timer_current_update %08x%08x",
752 vlapic->timer_initial, vlapic->timer_current,
753 (uint32_t)(vlapic->timer_current_update >> 32),
754 (uint32_t)vlapic->timer_current_update);
755 break;
757 case APIC_TDCR:
758 {
759 //FIXME clean this code
760 unsigned char tmp1,tmp2;
761 tmp1 = (val & 0xf);
762 tmp2 = ((tmp1 & 0x3 )|((tmp1 & 0x8) >>1)) + 1;
763 vlapic->timer_divide_counter = 0x1<<tmp2;
765 VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
766 "timer divider is 0x%x",
767 vlapic->timer_divide_counter);
768 }
769 break;
771 default:
772 printk("Local APIC Write to read-only register\n");
773 break;
774 }
775 }
777 static int vlapic_range(struct vcpu *v, unsigned long addr)
778 {
779 struct vlapic *vlapic = VLAPIC(v);
781 if (vlapic_global_enabled(vlapic) &&
782 (addr >= vlapic->base_address) &&
783 (addr <= (vlapic->base_address + VLOCAL_APIC_MEM_LENGTH)))
784 return 1;
786 return 0;
787 }
789 struct vmx_mmio_handler vlapic_mmio_handler = {
790 .check_handler = vlapic_range,
791 .read_handler = vlapic_read,
792 .write_handler = vlapic_write
793 };
795 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
796 {
797 /* When apic disabled */
798 if (!vlapic)
799 return;
801 if (vlapic->vcpu_id)
802 value &= ~MSR_IA32_APICBASE_BSP;
804 vlapic->apic_base_msr = value;
805 vlapic->base_address = vlapic_get_base_address(vlapic);
807 if (!(value & 0x800))
808 set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
810 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
811 "apic base msr = 0x%08x%08x,\nbase address = 0x%lx",
812 (uint32_t)(vlapic->apic_base_msr >> 32),
813 (uint32_t)vlapic->apic_base_msr,
814 vlapic->base_address);
815 }
817 static inline int vlapic_get_init_id(struct vcpu *v)
818 {
819 return v->vcpu_id;
820 }
822 void vlapic_timer_fn(void *data)
823 {
824 struct vlapic *vlapic;
826 vlapic = data;
827 if (!vlapic_enabled(vlapic)) return;
829 vlapic->timer_current_update = NOW();
831 if (vlapic_lvt_timer_enabled(vlapic)) {
832 if (!vlapic_irr_status(vlapic,
833 vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER))) {
834 test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER),
835 &vlapic->irr[0]);
836 }
837 else
838 vlapic->intr_pending_count[vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)]++;
839 evtchn_set_pending(vlapic->vcpu, iopacket_port(vlapic->domain));
840 }
842 vlapic->timer_current_update = NOW();
843 if (vlapic_lvt_timer_period(vlapic)) {
844 s_time_t offset;
846 vlapic->timer_current = vlapic->timer_initial;
847 offset = vlapic->timer_current * (262144/get_apic_bus_scale()) * vlapic->timer_divide_counter;
848 vlapic->vlapic_timer.expires = NOW() + offset;
849 set_ac_timer(&(vlapic->vlapic_timer), vlapic->vlapic_timer.expires);
850 }else {
851 vlapic->timer_current = 0;
852 }
854 VMX_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
855 "vlapic_timer_fn: now: %08x%08x expire %08x%08x init %x current %x",
856 (uint32_t)(NOW() >> 32),(uint32_t)NOW(),
857 (uint32_t)(vlapic->vlapic_timer.expires >> 32),
858 (uint32_t)vlapic->vlapic_timer.expires,
859 vlapic->timer_initial,vlapic->timer_current);
860 }
862 #if 0
863 static int
864 vlapic_check_direct_intr(struct vcpu *v, int * mode)
865 {
866 struct vlapic *vlapic = VLAPIC(v);
867 int type;
869 type = __fls(vlapic->direct_intr.deliver_mode);
870 if (type == -1)
871 return -1;
873 *mode = type;
874 return 0;
875 }
876 #endif
878 int
879 vlapic_accept_pic_intr(struct vcpu *v)
880 {
881 struct vlapic *vlapic = VLAPIC(v);
883 return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
884 }
886 int cpu_get_apic_interrupt(struct vcpu* v, int *mode)
887 {
888 struct vlapic *vlapic = VLAPIC(v);
890 if (vlapic && vlapic_enabled(vlapic)) {
891 int highest_irr = vlapic_find_highest_irr(vlapic);
893 if (highest_irr != -1 && highest_irr >= vlapic->processor_priority) {
894 if (highest_irr < 0x10) {
895 vlapic->err_status |= 0x20;
896 /* XXX What will happen if this vector illegal stil */
897 VMX_DBG_LOG(DBG_LEVEL_VLAPIC,
898 "vmx_intr_assist: illegal vector number %x err_status %x",
899 highest_irr, vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR));
901 set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR), &vlapic->irr[0]);
902 highest_irr = vlapic_lvt_vector(vlapic, VLAPIC_LVT_ERROR);
903 }
905 *mode = VLAPIC_DELIV_MODE_FIXED;
906 return highest_irr;
907 }
908 }
909 return -1;
910 }
912 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode) {
913 struct vlapic *vlapic = VLAPIC(v);
915 if (!vlapic)
916 return;
918 switch (deliver_mode) {
919 case VLAPIC_DELIV_MODE_FIXED:
920 case VLAPIC_DELIV_MODE_LPRI:
921 vlapic_set_isr(vlapic, vector);
922 vlapic_clear_irr(vlapic, vector);
923 vlapic_update_ppr(vlapic);
925 if (vector == vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER)) {
926 vlapic->intr_pending_count[vector]--;
927 if (vlapic->intr_pending_count[vector] > 0)
928 test_and_set_bit(vlapic_lvt_vector(vlapic, VLAPIC_LVT_TIMER),
929 &vlapic->irr[0]);
930 }
932 break;
933 /*XXX deal with these later */
935 case VLAPIC_DELIV_MODE_RESERVED:
936 printk("Ignore deliver mode 3 in vlapic_post_injection\n");
937 break;
939 case VLAPIC_DELIV_MODE_SMI:
940 case VLAPIC_DELIV_MODE_NMI:
941 case VLAPIC_DELIV_MODE_INIT:
942 case VLAPIC_DELIV_MODE_STARTUP:
943 vlapic->direct_intr.deliver_mode &= ~(1 << deliver_mode);
944 break;
946 default:
947 printk("<vlapic_post_injection> error deliver mode\n");
948 break;
949 }
950 }
952 static int vlapic_reset(struct vlapic *vlapic)
953 {
954 struct vcpu *v;
955 int apic_id, i;
957 ASSERT( vlapic != NULL );
959 v = vlapic->vcpu;
961 ASSERT( v != NULL );
963 apic_id = v->vcpu_id;
965 vlapic->domain = v->domain;
967 vlapic->id = apic_id;
969 vlapic->vcpu_id = v->vcpu_id;
971 vlapic->version = VLAPIC_VERSION;
973 vlapic->apic_base_msr = VLAPIC_BASE_MSR_INIT_VALUE;
975 if (apic_id == 0)
976 vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
978 vlapic->base_address = vlapic_get_base_address(vlapic);
980 for (i = 0; i < VLAPIC_LVT_NUM; i++)
981 vlapic->lvt[i] = VLAPIC_LVT_BIT_MASK;
983 vlapic->dest_format = 0xffffffffU;
985 vlapic->spurious_vec = 0xff;
987 vmx_vioapic_add_lapic(vlapic, v);
989 init_ac_timer(&vlapic->vlapic_timer,
990 vlapic_timer_fn, vlapic, v->processor);
992 #ifdef VLAPIC_NO_BIOS
993 /*
994 * XXX According to mp sepcific, BIOS will enable LVT0/1,
995 * remove it after BIOS enabled
996 */
997 if (!v->vcpu_id) {
998 vlapic->lvt[VLAPIC_LVT_LINT0] = 0x700;
999 vlapic->lvt[VLAPIC_LVT_LINT1] = 0x500;
1000 set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
1002 #endif
1004 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_reset: "
1005 "vcpu=%p id=%d vlapic_apic_base_msr=%08x%08x "
1006 "vlapic_base_address=%0lx",
1007 v, vlapic->id, (uint32_t)(vlapic->apic_base_msr >> 32),
1008 (uint32_t)vlapic->apic_base_msr, vlapic->base_address);
1010 return 1;
1013 int vlapic_init(struct vcpu *v)
1015 struct vlapic *vlapic = NULL;
1017 ASSERT( v != NULL );
1019 VMX_DBG_LOG(DBG_LEVEL_VLAPIC, "vlapic_init %d", v->vcpu_id);
1021 vlapic = xmalloc_bytes(sizeof(struct vlapic));
1022 if (!vlapic) {
1023 printk("malloc vlapic error for vcpu %x\n", v->vcpu_id);
1024 return -ENOMEM;
1027 memset(vlapic, 0, sizeof(struct vlapic));
1029 VLAPIC(v) = vlapic;
1031 vlapic->vcpu = v;
1033 vlapic_reset(vlapic);
1035 return 0;
1038 #endif /* CONFIG_VMX */