[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Merge xen-unstable into xen-ia64-unstable again (to get ioapic changes)
# HG changeset patch # User djm@xxxxxxxxxxxxxxx # Node ID 66dd96e90be4c2a66a98ed67ddd4ee8cec6bd599 # Parent d51b071bfcfcd9f77127b17b6516a118c33d4915 # Parent 25599e222c333565208c77c0d875bd56d6c719ef Merge xen-unstable into xen-ia64-unstable again (to get ioapic changes) diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/ldt.c Tue Nov 8 02:40:31 2005 @@ -18,7 +18,6 @@ #include <asm/system.h> #include <asm/ldt.h> #include <asm/desc.h> -#include <asm/mmu_context.h> #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -101,18 +100,13 @@ struct mm_struct * old_mm; int retval = 0; - memset(&mm->context, 0, sizeof(mm->context)); init_MUTEX(&mm->context.sem); + mm->context.size = 0; old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); retval = copy_ldt(&mm->context, &old_mm->context); up(&old_mm->context.sem); - } - if (retval == 0) { - spin_lock(&mm_unpinned_lock); - list_add(&mm->context.unpinned, &mm_unpinned); - spin_unlock(&mm_unpinned_lock); } return retval; } @@ -133,11 +127,6 @@ else kfree(mm->context.ldt); mm->context.size = 0; - } - if (!mm->context.pinned) { - spin_lock(&mm_unpinned_lock); - list_del(&mm->context.unpinned); - spin_unlock(&mm_unpinned_lock); } } diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/arch/xen/i386/mm/init.c --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/init.c Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/init.c Tue Nov 8 02:40:31 2005 @@ -376,7 +376,6 @@ __PAGE_KERNEL_EXEC |= _PAGE_GLOBAL; } - init_mm.context.pinned = 1; kernel_physical_mapping_init(pgd_base); remap_numa_kva(); @@ -689,6 +688,8 @@ #ifndef CONFIG_SMP zap_low_mappings(); #endif + + set_bit(PG_pinned, &virt_to_page(init_mm.pgd)->flags); } kmem_cache_t *pgd_cache; diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/pgtable.c Tue Nov 8 02:40:31 2005 @@ -26,6 +26,9 @@ #include <asm-xen/foreign_page.h> #include <asm/hypervisor.h> + +static void __pgd_pin(pgd_t *pgd); +static void __pgd_unpin(pgd_t *pgd); void show_mem(void) { @@ -299,6 +302,8 @@ { unsigned long flags; /* can be called from interrupt context */ + BUG_ON(test_bit(PG_pinned, &virt_to_page(pgd)->flags)); + if (HAVE_SHARED_KERNEL_PMD) return; @@ -311,6 +316,8 @@ { int i = 0; pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL); + + BUG_ON(test_bit(PG_pinned, &virt_to_page(pgd)->flags)); if (PTRS_PER_PMD == 1 || !pgd) return pgd; @@ -351,15 +358,9 @@ void pgd_free(pgd_t *pgd) { int i; - pte_t *ptep = virt_to_ptep(pgd); - - if (!pte_write(*ptep)) { - xen_pgd_unpin(__pa(pgd)); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)pgd, - pfn_pte(virt_to_phys(pgd)>>PAGE_SHIFT, PAGE_KERNEL), - 0)); - } + + if (test_bit(PG_pinned, &virt_to_page(pgd)->flags)) + __pgd_unpin(pgd); /* in the PAE case user pgd entries are overwritten before usage */ if (PTRS_PER_PMD > 1) { @@ -441,10 +442,7 @@ } #endif /* CONFIG_XEN_SHADOW_MODE */ -LIST_HEAD(mm_unpinned); -DEFINE_SPINLOCK(mm_unpinned_lock); - -static inline void mm_walk_set_prot(void *pt, pgprot_t flags) +static inline void pgd_walk_set_prot(void *pt, pgprot_t flags) { struct page *page = virt_to_page(pt); unsigned long pfn = page_to_pfn(page); @@ -456,103 +454,111 @@ pfn_pte(pfn, flags), 0)); } -static void mm_walk(struct mm_struct *mm, pgprot_t flags) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - int g,u,m; - - pgd = mm->pgd; +static void pgd_walk(pgd_t *pgd_base, pgprot_t flags) +{ + pgd_t *pgd = pgd_base; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + int g, u, m; + for (g = 0; g < USER_PTRS_PER_PGD; g++, pgd++) { if (pgd_none(*pgd)) continue; pud = pud_offset(pgd, 0); if (PTRS_PER_PUD > 1) /* not folded */ - mm_walk_set_prot(pud,flags); + pgd_walk_set_prot(pud,flags); for (u = 0; u < PTRS_PER_PUD; u++, pud++) { if (pud_none(*pud)) continue; pmd = pmd_offset(pud, 0); if (PTRS_PER_PMD > 1) /* not folded */ - mm_walk_set_prot(pmd,flags); + pgd_walk_set_prot(pmd,flags); for (m = 0; m < PTRS_PER_PMD; m++, pmd++) { if (pmd_none(*pmd)) continue; pte = pte_offset_kernel(pmd,0); - mm_walk_set_prot(pte,flags); + pgd_walk_set_prot(pte,flags); } } } + + BUG_ON(HYPERVISOR_update_va_mapping( + (unsigned long)pgd_base, + pfn_pte(virt_to_phys(pgd_base)>>PAGE_SHIFT, flags), + UVMF_TLB_FLUSH)); +} + +static void __pgd_pin(pgd_t *pgd) +{ + pgd_walk(pgd, PAGE_KERNEL_RO); + xen_pgd_pin(__pa(pgd)); + set_bit(PG_pinned, &virt_to_page(pgd)->flags); +} + +static void __pgd_unpin(pgd_t *pgd) +{ + xen_pgd_unpin(__pa(pgd)); + pgd_walk(pgd, PAGE_KERNEL); + clear_bit(PG_pinned, &virt_to_page(pgd)->flags); } void mm_pin(struct mm_struct *mm) { - spin_lock(&mm->page_table_lock); - - mm_walk(mm, PAGE_KERNEL_RO); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)mm->pgd, - pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL_RO), - UVMF_TLB_FLUSH)); - xen_pgd_pin(__pa(mm->pgd)); - mm->context.pinned = 1; - spin_lock(&mm_unpinned_lock); - list_del(&mm->context.unpinned); - spin_unlock(&mm_unpinned_lock); - - spin_unlock(&mm->page_table_lock); + spin_lock(&mm->page_table_lock); + __pgd_pin(mm->pgd); + spin_unlock(&mm->page_table_lock); } void mm_unpin(struct mm_struct *mm) { - spin_lock(&mm->page_table_lock); - - xen_pgd_unpin(__pa(mm->pgd)); - BUG_ON(HYPERVISOR_update_va_mapping( - (unsigned long)mm->pgd, - pfn_pte(virt_to_phys(mm->pgd)>>PAGE_SHIFT, PAGE_KERNEL), 0)); - mm_walk(mm, PAGE_KERNEL); - xen_tlb_flush(); - mm->context.pinned = 0; - spin_lock(&mm_unpinned_lock); - list_add(&mm->context.unpinned, &mm_unpinned); - spin_unlock(&mm_unpinned_lock); - - spin_unlock(&mm->page_table_lock); + spin_lock(&mm->page_table_lock); + __pgd_unpin(mm->pgd); + spin_unlock(&mm->page_table_lock); } void mm_pin_all(void) { - while (!list_empty(&mm_unpinned)) - mm_pin(list_entry(mm_unpinned.next, struct mm_struct, - context.unpinned)); + struct page *page; + for (page = pgd_list; page; page = (struct page *)page->index) { + if (!test_bit(PG_pinned, &page->flags)) + __pgd_pin((pgd_t *)page_address(page)); + } } void _arch_exit_mmap(struct mm_struct *mm) { - struct task_struct *tsk = current; - - task_lock(tsk); - - /* - * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() - * *much* faster this way, as no tlb flushes means bigger wrpt batches. - */ - if ( tsk->active_mm == mm ) - { - tsk->active_mm = &init_mm; - atomic_inc(&init_mm.mm_count); - - switch_mm(mm, &init_mm, tsk); - - atomic_dec(&mm->mm_count); - BUG_ON(atomic_read(&mm->mm_count) == 0); - } - - task_unlock(tsk); - - if ( mm->context.pinned && (atomic_read(&mm->mm_count) == 1) ) - mm_unpin(mm); -} + struct task_struct *tsk = current; + + task_lock(tsk); + + /* + * We aggressively remove defunct pgd from cr3. We execute unmap_vmas() + * *much* faster this way, as no tlb flushes means bigger wrpt batches. + */ + if (tsk->active_mm == mm) { + tsk->active_mm = &init_mm; + atomic_inc(&init_mm.mm_count); + + switch_mm(mm, &init_mm, tsk); + + atomic_dec(&mm->mm_count); + BUG_ON(atomic_read(&mm->mm_count) == 0); + } + + task_unlock(tsk); + + if (test_bit(PG_pinned, &virt_to_page(mm->pgd)->flags) && + (atomic_read(&mm->mm_count) == 1)) + mm_unpin(mm); +} + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/arch/xen/kernel/reboot.c --- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c Tue Nov 8 02:40:31 2005 @@ -129,8 +129,8 @@ preempt_disable(); #ifdef __i386__ + kmem_cache_shrink(pgd_cache); mm_pin_all(); - kmem_cache_shrink(pgd_cache); #endif __cli(); diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu.h Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu.h Tue Nov 8 02:40:31 2005 @@ -12,12 +12,7 @@ int size; struct semaphore sem; void *ldt; - unsigned pinned:1; - struct list_head unpinned; } mm_context_t; - -extern struct list_head mm_unpinned; -extern spinlock_t mm_unpinned_lock; /* mm/memory.c:exit_mmap hook */ extern void _arch_exit_mmap(struct mm_struct *mm); diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu_context.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu_context.h Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mmu_context.h Tue Nov 8 02:40:31 2005 @@ -53,7 +53,7 @@ struct mmuext_op _op[2], *op = _op; if (likely(prev != next)) { - if (!next->context.pinned) + if (!test_bit(PG_pinned, &virt_to_page(next->pgd)->flags)) mm_pin(next); /* stop flush ipis for the previous mm */ diff -r d51b071bfcfc -r 66dd96e90be4 linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgalloc.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgalloc.h Mon Nov 7 22:53:25 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgalloc.h Tue Nov 8 02:40:31 2005 @@ -7,12 +7,15 @@ #include <linux/mm.h> /* for struct page */ #include <asm/io.h> /* for phys_to_virt and page_to_pseudophys */ +/* Is this pagetable pinned? */ +#define PG_pinned PG_arch_1 + #define pmd_populate_kernel(mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) #define pmd_populate(mm, pmd, pte) \ do { \ - if (unlikely((mm)->context.pinned)) { \ + if (test_bit(PG_pinned, &virt_to_page((mm)->pgd)->flags)) { \ if (!PageHighMem(pte)) \ BUG_ON(HYPERVISOR_update_va_mapping( \ (unsigned long)__va(page_to_pfn(pte)<<PAGE_SHIFT),\ diff -r d51b071bfcfc -r 66dd96e90be4 xen/arch/x86/dm/i8259.c --- a/xen/arch/x86/dm/i8259.c Mon Nov 7 22:53:25 2005 +++ b/xen/arch/x86/dm/i8259.c Tue Nov 8 02:40:31 2005 @@ -33,6 +33,7 @@ #include <asm/vmx.h> #include <public/io/vmx_vpic.h> #include <asm/current.h> +#include <asm/vmx_vioapic.h> #include <asm/vmx_vlapic.h> /* set irq level. If an edge is detected, then the IRR is set to 1 */ @@ -124,6 +125,7 @@ { struct vmx_virpic *s = opaque; + vmx_vioapic_set_irq(current->domain, irq, level); pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); /* used for IOAPIC irqs */ if (s->alt_irq_func) @@ -135,6 +137,7 @@ { s->pics[1].irr |= (uint8_t)(irqs >> 8); s->pics[0].irr |= (uint8_t) irqs; + vmx_vioapic_do_irqs(current->domain, irqs); pic_update_irq(s); } @@ -142,6 +145,7 @@ { s->pics[1].irr &= ~(uint8_t)(irqs >> 8); s->pics[0].irr &= ~(uint8_t) irqs; + vmx_vioapic_do_irqs_clear(current->domain, irqs); pic_update_irq(s); } @@ -521,7 +525,13 @@ int is_pit_irq(struct vcpu *v, int irq, int type) { - int pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base; + int pit_vec; + + if (type == VLAPIC_DELIV_MODE_EXT) + pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base; + else + pit_vec = + v->domain->arch.vmx_platform.vmx_vioapic.redirtbl[0].RedirForm.vector; return (irq == pit_vec); } diff -r d51b071bfcfc -r 66dd96e90be4 xen/arch/x86/vmx_intercept.c --- a/xen/arch/x86/vmx_intercept.c Mon Nov 7 22:53:25 2005 +++ b/xen/arch/x86/vmx_intercept.c Tue Nov 8 02:40:31 2005 @@ -33,13 +33,15 @@ #ifdef CONFIG_VMX -struct vmx_mmio_handler vmx_mmio_handers[VMX_MMIO_HANDLER_NR] = -{ - { - .check_handler = vlapic_range, - .read_handler = vlapic_read, - .write_handler = vlapic_write - } +extern struct vmx_mmio_handler vlapic_mmio_handler; +extern struct vmx_mmio_handler vioapic_mmio_handler; + +#define VMX_MMIO_HANDLER_NR 2 + +struct vmx_mmio_handler *vmx_mmio_handlers[VMX_MMIO_HANDLER_NR] = +{ + &vlapic_mmio_handler, + &vioapic_mmio_handler }; static inline void vmx_mmio_access(struct vcpu *v, @@ -134,16 +136,16 @@ { struct vcpu *v = current; int i; - struct vmx_mmio_handler *handler = vmx_mmio_handers; /* XXX currently only APIC use intercept */ if ( !vmx_apic_support(v->domain) ) return 0; for ( i = 0; i < VMX_MMIO_HANDLER_NR; i++ ) { - if ( handler[i].check_handler(v, p->addr) ) { + if ( vmx_mmio_handlers[i]->check_handler(v, p->addr) ) { vmx_mmio_access(v, p, - handler[i].read_handler, handler[i].write_handler); + vmx_mmio_handlers[i]->read_handler, + vmx_mmio_handlers[i]->write_handler); return 1; } } diff -r d51b071bfcfc -r 66dd96e90be4 xen/arch/x86/vmx_vlapic.c --- a/xen/arch/x86/vmx_vlapic.c Mon Nov 7 22:53:25 2005 +++ b/xen/arch/x86/vmx_vlapic.c Tue Nov 8 02:40:31 2005 @@ -307,6 +307,11 @@ vlapic_clear_isr(vlapic, vector); vlapic_update_ppr(vlapic); + + if (test_and_clear_bit(vector, &vlapic->tmr[0])) { + extern void ioapic_update_EOI(struct domain *d, int vector); + ioapic_update_EOI(vlapic->domain, vector); + } } int vlapic_check_vector(struct vlapic *vlapic, @@ -543,8 +548,8 @@ } } -unsigned long vlapic_read(struct vcpu *v, unsigned long address, - unsigned long len) +static unsigned long vlapic_read(struct vcpu *v, unsigned long address, + unsigned long len) { unsigned int alignment; unsigned int tmp; @@ -585,8 +590,8 @@ return result; } -unsigned long vlapic_write(struct vcpu *v, unsigned long address, - unsigned long len, unsigned long val) +static void vlapic_write(struct vcpu *v, unsigned long address, + unsigned long len, unsigned long val) { struct vlapic *vlapic = VLAPIC(v); unsigned int offset = address - vlapic->base_address; @@ -758,10 +763,9 @@ printk("Local APIC Write to read-only register\n"); break; } - return 1; -} - -int vlapic_range(struct vcpu *v, unsigned long addr) +} + +static int vlapic_range(struct vcpu *v, unsigned long addr) { struct vlapic *vlapic = VLAPIC(v); @@ -772,6 +776,12 @@ return 0; } + +struct vmx_mmio_handler vlapic_mmio_handler = { + .check_handler = vlapic_range, + .read_handler = vlapic_read, + .write_handler = vlapic_write +}; void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) { @@ -963,6 +973,8 @@ vlapic->dest_format = 0xffffffffU; vlapic->spurious_vec = 0xff; + + vmx_vioapic_add_lapic(vlapic, v); init_ac_timer(&vlapic->vlapic_timer, vlapic_timer_fn, vlapic, v->processor); diff -r d51b071bfcfc -r 66dd96e90be4 xen/arch/x86/vmx_vmcs.c --- a/xen/arch/x86/vmx_vmcs.c Mon Nov 7 22:53:25 2005 +++ b/xen/arch/x86/vmx_vmcs.c Tue Nov 8 02:40:31 2005 @@ -28,6 +28,7 @@ #include <asm/processor.h> #include <asm/msr.h> #include <asm/vmx.h> +#include <asm/vmx_vioapic.h> #include <asm/flushtlb.h> #include <xen/event.h> #include <xen/kernel.h> @@ -255,6 +256,7 @@ if ( vmx_apic_support(d) ) { spin_lock_init(&d->arch.vmx_platform.round_robin_lock); + vmx_vioapic_init(d); } } diff -r d51b071bfcfc -r 66dd96e90be4 xen/include/asm-x86/vmx_intercept.h --- a/xen/include/asm-x86/vmx_intercept.h Mon Nov 7 22:53:25 2005 +++ b/xen/include/asm-x86/vmx_intercept.h Tue Nov 8 02:40:31 2005 @@ -18,10 +18,10 @@ unsigned long addr, unsigned long length); -typedef unsigned long (*vmx_mmio_write_t)(struct vcpu *v, - unsigned long addr, - unsigned long length, - unsigned long val); +typedef void (*vmx_mmio_write_t)(struct vcpu *v, + unsigned long addr, + unsigned long length, + unsigned long val); typedef int (*vmx_mmio_check_t)(struct vcpu *v, unsigned long addr); @@ -43,10 +43,6 @@ vmx_mmio_write_t write_handler; }; -#define VMX_MMIO_HANDLER_NR 1 - -extern struct vmx_mmio_handler vmx_mmio_handers[VMX_MMIO_HANDLER_NR]; - /* global io interception point in HV */ extern int vmx_io_intercept(ioreq_t *p, int type); extern int register_io_handler(unsigned long addr, unsigned long size, diff -r d51b071bfcfc -r 66dd96e90be4 xen/include/asm-x86/vmx_platform.h --- a/xen/include/asm-x86/vmx_platform.h Mon Nov 7 22:53:25 2005 +++ b/xen/include/asm-x86/vmx_platform.h Tue Nov 8 02:40:31 2005 @@ -24,6 +24,7 @@ #include <asm/e820.h> #include <asm/vmx_virpit.h> #include <asm/vmx_intercept.h> +#include <asm/vmx_vioapic.h> #include <public/io/vmx_vpic.h> #define MAX_OPERAND_NUM 2 @@ -85,6 +86,7 @@ struct vmx_virpit vmx_pit; struct vmx_io_handler vmx_io_handler; struct vmx_virpic vmx_pic; + struct vmx_vioapic vmx_vioapic; unsigned char round_info[256]; spinlock_t round_robin_lock; int interrupt_request; diff -r d51b071bfcfc -r 66dd96e90be4 xen/include/asm-x86/vmx_vlapic.h --- a/xen/include/asm-x86/vmx_vlapic.h Mon Nov 7 22:53:25 2005 +++ b/xen/include/asm-x86/vmx_vlapic.h Tue Nov 8 02:40:31 2005 @@ -225,14 +225,6 @@ extern void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); -int vlapic_range(struct vcpu *v, unsigned long addr); - -unsigned long vlapic_write(struct vcpu *v, unsigned long address, - unsigned long len, unsigned long val); - -unsigned long vlapic_read(struct vcpu *v, unsigned long address, - unsigned long len); - int vlapic_accept_pic_intr(struct vcpu *v); struct vlapic* apic_round_robin(struct domain *d, diff -r d51b071bfcfc -r 66dd96e90be4 xen/include/asm-x86/vmx_vmcs.h --- a/xen/include/asm-x86/vmx_vmcs.h Mon Nov 7 22:53:25 2005 +++ b/xen/include/asm-x86/vmx_vmcs.h Tue Nov 8 02:40:31 2005 @@ -284,7 +284,8 @@ #define DBG_LEVEL_VMMU (1 << 5) #define DBG_LEVEL_VLAPIC (1 << 6) #define DBG_LEVEL_VLAPIC_TIMER (1 << 7) -#define DBG_LEVEL_VLAPIC_INTERRUPT (1 << 7) +#define DBG_LEVEL_VLAPIC_INTERRUPT (1 << 8) +#define DBG_LEVEL_IOAPIC (1 << 9) extern unsigned int opt_vmx_debug_level; #define VMX_DBG_LOG(level, _f, _a...) \ diff -r d51b071bfcfc -r 66dd96e90be4 xen/arch/x86/dm/vmx_vioapic.c --- /dev/null Mon Nov 7 22:53:25 2005 +++ b/xen/arch/x86/dm/vmx_vioapic.c Tue Nov 8 02:40:31 2005 @@ -0,0 +1,608 @@ +/* +* Copyright (C) 2001 MandrakeSoft S.A. +* +* MandrakeSoft S.A. +* 43, rue d'Aboukir +* 75002 Paris - France +* http://www.linux-mandrake.com/ +* http://www.mandrakesoft.com/ +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* +* Yunhong Jiang <yunhong.jiang@xxxxxxxxx> +* Ported to xen by using virtual IRQ line. +*/ + +#include <asm/vmx_vioapic.h> +#include <asm/vmx_platform.h> + +#include <xen/config.h> +#include <xen/types.h> +#include <xen/mm.h> +#include <xen/xmalloc.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/sched.h> +#include <public/io/ioreq.h> +#include <asm/vmx.h> +#include <public/io/vmx_vpic.h> +#include <asm/current.h> + +static void ioapic_enable(vmx_vioapic_t *s, uint8_t enable) +{ + if (enable) + s->flags |= IOAPIC_ENABLE_FLAG; + else + s->flags &= ~IOAPIC_ENABLE_FLAG; +} + +static void ioapic_dump_redir(vmx_vioapic_t *s, uint8_t entry) +{ + ASSERT(s); + + RedirStatus redir = s->redirtbl[entry]; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_dump_redir " + "entry %x vector %x deliver_mod %x destmode %x delivestatus %x " + "polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n", + entry, redir.RedirForm.vector, redir.RedirForm.deliver_mode, + redir.RedirForm.destmode, redir.RedirForm.delivestatus, + redir.RedirForm.polarity, redir.RedirForm.remoteirr, + redir.RedirForm.trigmod, redir.RedirForm.mask, + redir.RedirForm.dest_id); +} + +#ifdef VMX_DOMAIN_SAVE_RESTORE +void ioapic_save(QEMUFile* f, void* opaque) +{ + printk("no implementation for ioapic_save\n"); +} + +int ioapic_load(QEMUFile* f, void* opaque, int version_id) +{ + printk("no implementation for ioapic_load\n"); + return 0; +} +#endif + +static unsigned long vmx_vioapic_read_indirect(struct vmx_vioapic *s, + unsigned long addr, + unsigned long length) +{ + unsigned long result = 0; + + ASSERT(s); + + switch (s->ioregsel) { + case IOAPIC_REG_VERSION: + result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16) + | (IOAPIC_VERSION_ID & 0x0f)); + break; + +#ifndef __ia64__ + case IOAPIC_REG_APIC_ID: + result = ((s->id & 0xf) << 24); + break; + + case IOAPIC_REG_ARB_ID: + /* XXX how arb_id used on p4? */ + result = ((s->id & 0xf) << 24); + break; +#endif + + default: + { + uint32_t redir_index = 0; + uint64_t redir_content = 0; + + redir_index = (s->ioregsel - 0x10) >> 1; + + if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) { + redir_content = s->redirtbl[redir_index].value; + + result = (s->ioregsel & 0x1)? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; + } else { + printk("upic_mem_readl:undefined ioregsel %x\n", + s->ioregsel); + domain_crash_synchronous(); + } + break; + } + } /* switch */ + + return result; +} + +static unsigned long vmx_vioapic_read(struct vcpu *v, + unsigned long addr, + unsigned long length) +{ + struct vmx_vioapic *s = &(v->domain->arch.vmx_platform.vmx_vioapic); + uint32_t result = 0; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_read addr %lx\n", addr); + + ASSERT(s); + + addr &= 0xff; + + switch (addr) { + case IOAPIC_REG_SELECT: + result = s->ioregsel; + break; + + case IOAPIC_REG_WINDOW: + result = vmx_vioapic_read_indirect(s, addr, length); + break; + + default: + break; + } + + return result; +} + +static void vmx_vioapic_write_indirect(struct vmx_vioapic *s, + unsigned long addr, + unsigned long length, + unsigned long val) +{ + switch (s->ioregsel) { + case IOAPIC_REG_VERSION: + printk("vmx_vioapic_write_indirect: version register read only\n"); + break; + +#ifndef __ia64__ + case IOAPIC_REG_APIC_ID: + s->id = (val >> 24) & 0xf; + break; + + case IOAPIC_REG_ARB_ID: + s->arb_id = val; + break; +#endif + + default: + { + uint32_t redir_index = 0; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_write_indirect " + "change redir index %x val %lx\n", + redir_index, val); + + redir_index = (s->ioregsel - 0x10) >> 1; + + if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) { + uint64_t redir_content; + + redir_content = s->redirtbl[redir_index].value; + + if (s->ioregsel & 0x1) + redir_content = (((uint64_t)val & 0xffffffff) << 32) | + (redir_content & 0xffffffff); + else + redir_content = ((redir_content >> 32) << 32) | + (val & 0xffffffff); + s->redirtbl[redir_index].value = redir_content; + } else { + printk("vmx_vioapic_write_indirect " + "error register %x\n", s->ioregsel); + } + break; + } + } /* switch */ +} + +static void vmx_vioapic_write(struct vcpu *v, + unsigned long addr, + unsigned long length, + unsigned long val) +{ + vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic); + + ASSERT(s); + + addr &= 0xff; + + switch (addr) { + case IOAPIC_REG_SELECT: + s->ioregsel = val; + break; + + case IOAPIC_REG_WINDOW: + vmx_vioapic_write_indirect(s, addr, length, val); + break; + +#ifdef __ia64__ + case IOAPIC_REG_EOI: + ioapic_update_EOI(v->domain, val); + break; +#endif + + default: + break; + } +} + +static int vmx_vioapic_range(struct vcpu *v, unsigned long addr) +{ + vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic); + + if ((s->flags & IOAPIC_ENABLE_FLAG) && + (addr >= s->base_address && + (addr <= s->base_address + IOAPIC_MEM_LENGTH))) + return 1; + else + return 0; +} + +struct vmx_mmio_handler vioapic_mmio_handler = { + .check_handler = vmx_vioapic_range, + .read_handler = vmx_vioapic_read, + .write_handler = vmx_vioapic_write +}; + +static void vmx_vioapic_reset(vmx_vioapic_t *s) +{ + int i; + + memset(s, 0, sizeof(vmx_vioapic_t)); + + for (i = 0; i < IOAPIC_NUM_PINS; i++) + s->redirtbl[i].RedirForm.mask = 0x1; +} + +static void ioapic_update_config(vmx_vioapic_t *s, + unsigned long address, + uint8_t enable) +{ + ASSERT(s); + + ioapic_enable(s, enable); + + if (address != s->base_address) + s->base_address = address; +} + +static int ioapic_inj_irq(vmx_vioapic_t *s, + struct vlapic * target, + uint8_t vector, + uint8_t trig_mode, + uint8_t delivery_mode) +{ + int result = 0; + + ASSERT(s && target); + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_inj_irq " + "irq %d trig %d delive mode %d\n", + vector, trig_mode, delivery_mode); + + switch (delivery_mode) { + case VLAPIC_DELIV_MODE_FIXED: + case VLAPIC_DELIV_MODE_LPRI: + if (test_and_set_bit(vector, &target->irr[0]) && trig_mode == 1) { + /* the level interrupt should not happen before it is cleard */ + printk("<ioapic_inj_irq> level interrupt happen before cleard\n"); + } + if (trig_mode) + test_and_set_bit(vector, &target->tmr[0]); + result = 1; + break; + default: + printk("<ioapic_inj_irq> error delivery mode %d\n", + delivery_mode); + break; + } + + return result; +} + +#ifndef __ia64__ +static int ioapic_match_logical_addr(vmx_vioapic_t *s, int number, uint8_t dest) +{ + int result = 0; + + ASSERT(s && s->lapic_info[number]); + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_match_logical_addr " + "number %i dest %x\n", + number, dest); + + switch (((s->lapic_info[number]->dest_format >> 28) & 0xf)) { + case 0xf: + result = + (dest & ((s->lapic_info[number]->logical_dest >> 24) & 0xff)) != 0; + break; + case 0x0: + /* Should we support flat cluster mode ?*/ + if ( ((s->lapic_info[number]->logical_dest >> 28) + == ((dest >> 0x4) & 0xf)) && + (((s->lapic_info[number]->logical_dest >> 24) & 0xf) + & (dest & 0xf)) ) + result = 1; + break; + default: + printk("error DFR value for %x local apic\n", number); + break; + } + + return result; +} +#else +extern int ioapic_match_logical_addr(vmx_vioapic_t *s, int number, uint8_t dest); +#endif + +static uint32_t ioapic_get_delivery_bitmask(vmx_vioapic_t *s, + uint16_t dest, + uint8_t dest_mode, + uint8_t vector, + uint8_t delivery_mode) +{ + uint32_t mask = 0; + int i; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask " + "dest %d dest_mode %d " + "vector %d del_mode %d, lapic_count %d\n", + dest, dest_mode, vector, delivery_mode, s->lapic_count); + + ASSERT(s); + + if (dest_mode == 0) { /* Physical mode */ + for (i = 0; i < s->lapic_count; i++) { + if (s->lapic_info[i]->id == dest) { + mask = 1 << i; + break; + } + } + } else { + /* logical destination. call match_logical_addr for each APIC. */ + if (dest != 0) { + for (i=0; i< s->lapic_count; i++) { + if ( s->lapic_info[i] && + ioapic_match_logical_addr(s, i, dest) ) { + mask |= (1<<i); + } + } + } + } + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask " + "mask %x\n", mask); + + return mask; +} + +static void ioapic_deliver(vmx_vioapic_t *s, int irqno) +{ + uint16_t dest = s->redirtbl[irqno].RedirForm.dest_id; + uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode; + uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode; + uint8_t vector = s->redirtbl[irqno].RedirForm.vector; + uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod; + uint32_t deliver_bitmask; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "IOAPIC deliver: " + "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n", + dest, dest_mode, delivery_mode, vector, trig_mode); + + deliver_bitmask = + ioapic_get_delivery_bitmask(s, dest, dest_mode, vector, delivery_mode); + + if (!deliver_bitmask) { + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic deliver " + "no target on destination\n"); + + return; + } + + switch (delivery_mode) { + case VLAPIC_DELIV_MODE_LPRI: + { + struct vlapic* target; + + target = apic_round_robin( + s->domain, dest_mode, vector, deliver_bitmask); + ioapic_inj_irq(s, target, vector, trig_mode, delivery_mode); + break; + } + + case VLAPIC_DELIV_MODE_FIXED: + case VLAPIC_DELIV_MODE_EXT: + { + uint8_t bit; + for (bit = 0; bit < s->lapic_count; bit++) { + if (deliver_bitmask & (1 << bit)) { + if (s->lapic_info[bit]) { + ioapic_inj_irq(s, s->lapic_info[bit], + vector, trig_mode, delivery_mode); + } + } + } + break; + } + + case VLAPIC_DELIV_MODE_SMI: + case VLAPIC_DELIV_MODE_NMI: + case VLAPIC_DELIV_MODE_INIT: + case VLAPIC_DELIV_MODE_STARTUP: + default: + printk("Not support delivey mode %d\n", delivery_mode); + break; + } +} + +static int ioapic_get_highest_irq(vmx_vioapic_t *s) +{ + uint32_t irqs; + + ASSERT(s); + + irqs = s->irr & ~s->isr; + return __fls(irqs); +} + + +static void service_ioapic(vmx_vioapic_t *s) +{ + int irqno; + + while ((irqno = ioapic_get_highest_irq(s)) != -1) { + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "service_ioapic " + "highest irqno %x\n", irqno); + + if (!s->redirtbl[irqno].RedirForm.mask) { + ioapic_deliver(s, irqno); + } + + if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) { + s->isr |= (1 << irqno); + } + + s->irr &= ~(1 << irqno); + } +} + +void vmx_vioapic_do_irqs(struct domain *d, uint16_t irqs) +{ + vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic); + + if (!vmx_apic_support(d)) + return; + + s->irr |= irqs; + service_ioapic(s); +} + +void vmx_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs) +{ + vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic); + + if (!vmx_apic_support(d)) + return; + + s->irr &= ~irqs; + service_ioapic(s); +} + +void vmx_vioapic_set_irq(struct domain *d, int irq, int level) +{ + vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic); + + if (!vmx_apic_support(d)) + return ; + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq " + "irq %x level %x\n", irq, level); + + if (irq < 0 || irq >= IOAPIC_NUM_PINS) { + printk("ioapic_set_irq irq %x is illegal\n", irq); + domain_crash_synchronous(); + } + + if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask) + return; + + ioapic_dump_redir(s, irq); + + if (irq >= 0 && irq < IOAPIC_NUM_PINS) { + uint32_t bit = 1 << irq; + if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) { + if (level) + s->irr |= bit; + else + s->irr &= ~bit; + } else { + if (level) + /* XXX No irr clear for edge interrupt */ + s->irr |= bit; + } + } + + service_ioapic(s); +} + +/* XXX If level interrupt, use vector->irq table for performance */ +static int get_redir_num(vmx_vioapic_t *s, int vector) +{ + int i = 0; + + ASSERT(s); + + for(i = 0; i < IOAPIC_NUM_PINS - 1; i++) { + if (s->redirtbl[i].RedirForm.vector == vector) + return i; + } + + return -1; +} + +void ioapic_update_EOI(struct domain *d, int vector) +{ + vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic); + int redir_num; + + if ((redir_num = get_redir_num(s, vector)) == -1) { + printk("Can't find redir item for %d EOI \n", vector); + return; + } + + if (!test_and_clear_bit(redir_num, &s->isr)) { + printk("redir %d not set for %d EOI\n", redir_num, vector); + return; + } +} + +int vmx_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v) +{ + vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic); + + if (v->vcpu_id != s->lapic_count) { + printk("vmx_vioapic_add_lapic " + "cpu_id not match vcpu_id %x lapic_count %x\n", + v->vcpu_id, s->lapic_count); + domain_crash_synchronous(); + } + + s->lapic_info[s->lapic_count ++] = vlapic; + + return s->lapic_count; +} + +vmx_vioapic_t * vmx_vioapic_init(struct domain *d) +{ + int i = 0; + vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic); + + VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_init\n"); + + vmx_vioapic_reset(s); + + s->domain = d; + + for (i = 0; i < MAX_LAPIC_NUM; i++) + s->lapic_info[i] = NULL; + + /* Remove after GFW ready */ + ioapic_update_config(s, IOAPIC_DEFAULT_BASE_ADDRESS, 1); + + return s; +} diff -r d51b071bfcfc -r 66dd96e90be4 xen/include/asm-x86/vmx_vioapic.h --- /dev/null Mon Nov 7 22:53:25 2005 +++ b/xen/include/asm-x86/vmx_vioapic.h Tue Nov 8 02:40:31 2005 @@ -0,0 +1,136 @@ +/* + * + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _IOAPIC_H_ +#define _IOAPIC_H_ + +#include <xen/config.h> +#include <xen/types.h> +#include <xen/smp.h> + +#ifndef __ia64__ +#define IOAPIC_VERSION_ID 0x11 +#else +#define IOAPIC_VERSION_ID 0x21 +#endif + +#define IOAPIC_NUM_PINS 24 +#define MAX_LAPIC_NUM 32 + +#define IOAPIC_LEVEL_TRIGGER 1 + +#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 +#define IOAPIC_MEM_LENGTH 0x100 + +#define IOAPIC_ENABLE_MASK 0x0 +#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK) +#define IOAPICEnabled(s) (s->flags & IOAPIC_ENABLE_FLAG) + +#define IOAPIC_REG_SELECT 0x0 +#define IOAPIC_REG_WINDOW 0x10 + +#ifdef __ia64__ +#define IOAPIC_REG_ASSERTION 0x20 +#define IOAPIC_REG_EOI 0x40 +#endif + +#ifndef __ia64__ +#define IOAPIC_REG_APIC_ID 0x0 +#define IOAPIC_REG_ARB_ID 0x2 +#endif + +#define IOAPIC_REG_VERSION 0x1 + +#ifdef __ia64__ +typedef union RedirStatus +{ + uint64_t value; + struct { + uint16_t dest_id; + uint8_t reserved[3]; + uint8_t reserve:7; + uint8_t mask:1; /* interrupt mask*/ + uint8_t trigmod:1; + uint8_t remoteirr:1; + uint8_t polarity:1; + uint8_t delivestatus:1; + uint8_t destmode:1; + uint8_t deliver_mode:3; + uint8_t vector; + } RedirForm; +} RedirStatus; +#else +typedef union RedirStatus +{ + uint64_t value; + struct { + uint8_t vector; + uint8_t deliver_mode:3; + uint8_t destmode:1; + uint8_t delivestatus:1; + uint8_t polarity:1; + uint8_t remoteirr:1; + uint8_t trigmod:1; + uint8_t mask:1; /* interrupt mask*/ + uint8_t reserve:7; + uint8_t reserved[4]; + uint8_t dest_id; + } RedirForm; +} RedirStatus; +#endif + +#define IOAPIC_MEM_LENGTH 0x100 +#define IOAPIC_ENABLE_MASK 0x0 +#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK) +#define MAX_LAPIC_NUM 32 + +typedef struct vmx_vioapic { + uint32_t ioregsel; + uint32_t irr; + uint32_t isr; /* This is used for level trigger */ + uint32_t flags; + uint32_t lapic_count; + uint32_t id; + uint32_t arb_id; + unsigned long base_address; + RedirStatus redirtbl[IOAPIC_NUM_PINS]; + struct vlapic *lapic_info[MAX_LAPIC_NUM]; + struct domain *domain; +} vmx_vioapic_t; + +vmx_vioapic_t *vmx_vioapic_init(struct domain *d); + +void vmx_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs); +void vmx_vioapic_do_irqs(struct domain *d, uint16_t irqs); +void vmx_vioapic_set_irq(struct domain *d, int irq, int level); + +int vmx_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v); + +#ifdef VMX_DOMAIN_SAVE_RESTORE +void ioapic_save(QEMUFile* f, void* opaque); +int ioapic_load(QEMUFile* f, void* opaque, int version_id); +#endif + +#endif diff -r d51b071bfcfc -r 66dd96e90be4 tools/ioemu/hw/ioapic.c --- a/tools/ioemu/hw/ioapic.c Mon Nov 7 22:53:25 2005 +++ /dev/null Tue Nov 8 02:40:31 2005 @@ -1,704 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2001 MandrakeSoft S.A. -// -// MandrakeSoft S.A. -// 43, rue d'Aboukir -// 75002 Paris - France -// http://www.linux-mandrake.com/ -// http://www.mandrakesoft.com/ -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#include "vl.h" -#include "ioapic.h" - -#ifdef __OS -#undef __OS -#endif -#ifdef __i386__ -#define __OS "l" -#else -#define __OS "q" -#endif -#define ADDR (*(volatile long *) addr) - -#ifdef IOAPIC_DEBUG -#define IOAPIC_LOG(a...) fprintf(logfile, ##a) -#else -#define IOAPIC_LOG(a...) -#endif - -static IOAPICState *ioapic; - -#define IOAPIC_ERR(a...) fprintf(logfile, ##a) -static __inline__ int test_and_set_bit(long nr, volatile void * addr) -{ - long oldbit; - - __asm__ __volatile__( - "bts"__OS" %2,%1\n\tsbb"__OS" %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr) : "memory"); - return oldbit; -} - -static __inline__ int test_and_clear_bit(long nr, volatile void * addr) -{ - long oldbit; - - __asm__ __volatile__( LOCK_PREFIX - "btr"__OS" %2,%1\n\tsbb"__OS" %0,%0" - :"=r" (oldbit),"=m" (ADDR) - :"dIr" (nr) : "memory"); - return oldbit; -} - -static __inline__ void clear_bit(long nr, volatile void * addr) -{ - __asm__ __volatile__( - "btr"__OS" %1,%0" - :"=m" (ADDR) - :"Ir" (nr)); -} - -static inline -void get_shareinfo_apic_msg(vlapic_info *share_info){ - while(test_and_set_bit(VL_STATE_MSG_LOCK, &share_info->vl_state)){}; -} - -static inline -void put_shareinfo_apic_msg(vlapic_info *share_info){ - clear_bit(VL_STATE_MSG_LOCK, &share_info->vl_state); -} -static inline -void get_shareinfo_eoi(vlapic_info *share_info){ - while(test_and_set_bit(VL_STATE_EOI_LOCK, &share_info->vl_state)){}; -} - -static inline -void put_shareinfo_eoi(vlapic_info *share_info){ - clear_bit(VL_STATE_EOI_LOCK, &share_info->vl_state); -} - - -static inline -void get_shareinfo_ext(vlapic_info *share_info){ - while(test_and_set_bit(VL_STATE_EXT_LOCK, &share_info->vl_state)); -} - -static inline -void put_shareinfo_ext(vlapic_info *share_info){ - clear_bit(VL_STATE_EXT_LOCK, &share_info->vl_state); -} - - -static __inline__ int test_bit(int nr, uint32_t value){ - return value & (1 << nr); -} - -static void ioapic_enable(IOAPICState *s, uint8_t enable) -{ - if (!enable ^ IOAPICEnabled(s)) return; - if(enable) - s->flags |= IOAPIC_ENABLE_FLAG; - else - s->flags &= ~IOAPIC_ENABLE_FLAG; -} - -#ifdef IOAPIC_DEBUG -static void -ioapic_dump_redir(IOAPICState *s, uint8_t entry) -{ - if (!s) - return; - - RedirStatus redir = s->redirtbl[entry]; - - fprintf(logfile, "entry %x: " - "vector %x deliver_mod %x destmode %x delivestatus %x " - "polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n", - entry, - redir.RedirForm.vector, redir.RedirForm.deliver_mode, - redir.RedirForm.destmode, redir.RedirForm.delivestatus, - redir.RedirForm.polarity, redir.RedirForm.remoteirr, - redir.RedirForm.trigmod, redir.RedirForm.mask, - redir.RedirForm.dest_id); -} - -static void -ioapic_dump_shareinfo(IOAPICState *s , int number) -{ - if (!s || !s->lapic_info[number]) - return; - vlapic_info *m = s->lapic_info[number]; - IOAPIC_LOG("lapic_info %x : " - "vl_lapic_id %x vl_logical_dest %x vl_dest_format %x vl_arb_id %x\n", - number, m->vl_lapic_id, m->vl_logical_dest, m->vl_dest_format, m->vl_arb_id ); -} -#endif - -static void -ioapic_save(QEMUFile* f,void* opaque) -{ - IOAPIC_ERR("no implementation for ioapic_save\n"); -} - -static -int ioapic_load(QEMUFile* f,void* opaque,int version_id) -{ - IOAPIC_ERR("no implementation for ioapic_load\n"); - return 0; -} - -uint32_t -ioapic_mem_readb(void *opaque, target_phys_addr_t addr) -{ - IOAPIC_ERR("ioapic_mem_readb\n"); - return 0; -} - -uint32_t -ioapic_mem_readw(void *opaque, target_phys_addr_t addr) -{ - IOAPIC_ERR("ioapic_mem_readw\n"); - return 0; -} - -static -void ioapic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - IOAPIC_ERR("ioapic_mem_writeb\n"); -} - -static -void ioapic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - IOAPIC_ERR("ioapic_mem_writew\n"); -} - -static -uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - unsigned short ioregsel; - IOAPICState *s = opaque; - uint32_t result = 0; - uint32_t redir_index = 0; - uint64_t redir_content = 0; - - IOAPIC_LOG("apic_mem_readl addr %x\n", addr); - if (!s){ - IOAPIC_ERR("null pointer for apic_mem_readl\n"); - return result; - } - - addr &= 0xff; - if(addr == 0x00){ - result = s->ioregsel; - return result; - }else if (addr != 0x10){ - IOAPIC_ERR("apic_mem_readl address error\n"); - return result; - } - - ioregsel = s->ioregsel; - - switch (ioregsel){ - case IOAPIC_REG_APIC_ID: - result = ((s->id & 0xf) << 24); - break; - case IOAPIC_REG_VERSION: - result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16) - | (IOAPIC_VERSION_ID & 0x0f)); - break; - case IOAPIC_REG_ARB_ID: - //FIXME - result = ((s->id & 0xf) << 24); - break; - default: - redir_index = (ioregsel - 0x10) >> 1; - if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){ - redir_content = s->redirtbl[redir_index].value; - result = (ioregsel & 0x1)? - (redir_content >> 32) & 0xffffffff : - redir_content & 0xffffffff; - }else{ - IOAPIC_ERR( - "upic_mem_readl:undefined ioregsel %x\n", - ioregsel); - } - } - return result; -} - -static -void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - IOAPICState *s = opaque; - uint32_t redir_index = 0; - uint64_t redir_content; - - IOAPIC_LOG("apic_mem_writel addr %x val %x\n", addr, val); - - if (!s){ - IOAPIC_ERR("apic_mem_writel: null opaque\n"); - return; - } - - addr &= 0xff; - if (addr == 0x00){ - s->ioregsel = val; - return; - }else if (addr != 0x10){ - IOAPIC_ERR("apic_mem_writel: unsupported address\n"); - } - - switch (s->ioregsel){ - case IOAPIC_REG_APIC_ID: - s->id = (val >> 24) & 0xf; - break; - case IOAPIC_REG_VERSION: - IOAPIC_ERR("apic_mem_writel: version register read only\n"); - break; - case IOAPIC_REG_ARB_ID: - s->arb_id = val; - break; - default: - redir_index = (s->ioregsel - 0x10) >> 1; -// IOAPIC_LOG("apic_mem_write: change redir :index %x before %lx, val %x\n", redir_index, s->redirtbl[redir_index].value, val); - if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){ - redir_content = s->redirtbl[redir_index].value; - if (s->ioregsel & 0x1) - redir_content = (((uint64_t)val & 0xffffffff) << 32) | (redir_content & 0xffffffff); - else - redir_content = ((redir_content >> 32) << 32) | (val & 0xffffffff); - s->redirtbl[redir_index].value = redir_content; - }else { - IOAPIC_ERR("apic_mem_writel: error register\n"); - } - //IOAPIC_LOG("after value is %lx\n", s->redirtbl[redir_index].value); - } -} - -static CPUReadMemoryFunc *ioapic_mem_read[3] = { - ioapic_mem_readb, - ioapic_mem_readw, - ioapic_mem_readl, -}; - -static CPUWriteMemoryFunc *ioapic_mem_write[3] = { - ioapic_mem_writeb, - ioapic_mem_writew, - ioapic_mem_writel, -}; - -void -IOAPICReset(IOAPICState *s) -{ - int i; - if (!s) - return ; - - memset(s, 0, sizeof(IOAPICState)); - - for (i = 0; i < IOAPIC_NUM_PINS; i++) - s->redirtbl[i].RedirForm.mask = 0x1; -// IOAPIC_LOG("after Reset %lx\n", s->redirtbl[0].value); -} - -void -ioapic_update_config(IOAPICState *s, unsigned long address, uint8_t enable) -{ - int ioapic_mem; - if (!s) - return; - - ioapic_enable(s, enable); - - if (address != s->base_address){ - ioapic_mem = cpu_register_io_memory(0, ioapic_mem_read, ioapic_mem_write, s); - cpu_register_physical_memory(address, IOAPIC_MEM_LENGTH, ioapic_mem); - s->base_address = ioapic_mem; - } -} - -#define direct_intr(mode) \ - (mode == VLAPIC_DELIV_MODE_SMI || \ - mode == VLAPIC_DELIV_MODE_NMI || \ - mode == VLAPIC_DELIV_MODE_INIT ||\ - mode == VLAPIC_DELIV_MODE_STARTUP) - -int -ioapic_inj_irq(IOAPICState *s, uint8_t dest, uint8_t vector, uint8_t trig_mode, uint8_t delivery_mode) -{ - int msg_count; - if (!s || !s->lapic_info[dest]){ - IOAPIC_ERR("ioapic_inj_irq NULL parameter\n"); - return 0; - } - IOAPIC_LOG("ioapic_inj_irq %d , trig %d delive mode %d\n", - vector, trig_mode, delivery_mode); - switch(delivery_mode){ - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: - get_shareinfo_apic_msg(s->lapic_info[dest]); - msg_count = s->lapic_info[dest]->apic_msg_count; - s->lapic_info[dest]->vl_apic_msg[msg_count].deliv_mode = delivery_mode; - s->lapic_info[dest]->vl_apic_msg[msg_count].level = trig_mode; - s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector; - s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector; - s->lapic_info[dest]->apic_msg_count ++; - put_shareinfo_apic_msg(s->lapic_info[dest]); - break; - case VLAPIC_DELIV_MODE_EXT: -/* get_shareinfo_ext(s->lapic_info[dest]); - test_and_set_bit(vector, &s->lapic_info[dest]->vl_ext_intr[0]); - put_shareinfo_ext(s->lapic_info[dest]);*/ - IOAPIC_ERR("<ioapic_inj_irq> Ext interrupt\n"); - return 0; - default: - IOAPIC_ERR("<ioapic_inj_irq> error delivery mode\n"); - break; - } - return 1; -} - -int -ioapic_match_logical_addr(IOAPICState *s, int number, uint8_t address) -{ - if(!s || !s->lapic_info[number]){ - IOAPIC_ERR("ioapic_match_logical_addr NULL parameter: " - "number: %i s %p address %x\n", - number, s, address); - return 0; - } - IOAPIC_LOG("ioapic_match_logical_addr number %i address %x\n", - number, address); - - if (((s->lapic_info[number]->vl_dest_format >> 28 ) & 0xf) != 0xf) { - IOAPIC_ERR("ioapic_match_logical_addr: cluster model not implemented still%x" - ,s->lapic_info[number]->vl_dest_format); -#ifdef IOAPIC_DEBUG - ioapic_dump_shareinfo(s, number); -#endif - return 0; - } - return ((address & ((s->lapic_info[number]->vl_logical_dest >> 24) & 0xff)) != 0); -} - -int -ioapic_get_apr_lowpri(IOAPICState *s, int number) -{ - if(!s || !s->lapic_info[number]){ - IOAPIC_ERR("ioapic_get_apr_lowpri NULL parameter\n"); - return 0; - } - return s->lapic_info[number]->vl_arb_id; -} - -uint32_t -ioapic_get_delivery_bitmask(IOAPICState *s, -uint8_t dest, uint8_t dest_mode, uint8_t vector, uint8_t delivery_mode) -{ - uint32_t mask = 0; - int low_priority = 256, selected = -1, i; - fprintf(logfile, "<ioapic_get_delivery_bitmask>: dest %d dest_mode %d" - "vector %d del_mode %d, lapic_count %d\n", - dest, dest_mode, vector, delivery_mode, s->lapic_count); - if (!s) return mask; - if (dest_mode == 0) { //Physical mode - if ((dest < s->lapic_count) && s->lapic_info[dest]) - mask = 1 << dest; - } - else { - /* logical destination. call match_logical_addr for each APIC. */ - if (dest == 0) return 0; - for (i=0; i< s->lapic_count; i++) { - //FIXME focus one, since no such issue on IPF, shoudl we add it? - if ( s->lapic_info[i] && ioapic_match_logical_addr(s, i, dest)){ - if (delivery_mode != APIC_DM_LOWPRI) - mask |= (1<<i); - else { - if (low_priority > ioapic_get_apr_lowpri(s, i)){ - low_priority = ioapic_get_apr_lowpri(s, i); - selected = i; - } - fprintf(logfile, "%d low_priority %d apr %d select %d\n", - i, low_priority, ioapic_get_apr_lowpri(s, i), selected); - } - } - } - if (delivery_mode == APIC_DM_LOWPRI && (selected != -1)) - mask |= (1<< selected); - } - return mask; -} - -void -ioapic_deliver(IOAPICState *s, int irqno){ - uint8_t dest = s->redirtbl[irqno].RedirForm.dest_id; - uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode; - uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode; - uint8_t vector = s->redirtbl[irqno].RedirForm.vector; - uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod; - uint8_t bit; - uint32_t deliver_bitmask; - - IOAPIC_LOG("IOAPIC deliver: " - "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n", - dest, dest_mode, delivery_mode, vector, trig_mode); - - deliver_bitmask = - ioapic_get_delivery_bitmask(s, dest, dest_mode, vector, delivery_mode); - - IOAPIC_LOG("ioapic_get_delivery_bitmask return %x\n", deliver_bitmask); - if (!deliver_bitmask){ - IOAPIC_ERR("Ioapic deliver, no target on destination\n"); - return ; - } - - switch (delivery_mode){ - case VLAPIC_DELIV_MODE_FIXED: - case VLAPIC_DELIV_MODE_LPRI: - case VLAPIC_DELIV_MODE_EXT: - break; - case VLAPIC_DELIV_MODE_SMI: - case VLAPIC_DELIV_MODE_NMI: - case VLAPIC_DELIV_MODE_INIT: - case VLAPIC_DELIV_MODE_STARTUP: - default: - IOAPIC_ERR("Not support delivey mode %d\n", delivery_mode); - return ; - } - - for (bit = 0; bit < s->lapic_count; bit++){ - if (deliver_bitmask & (1 << bit)){ - if (s->lapic_info[bit]){ - ioapic_inj_irq(s, bit, vector, trig_mode, delivery_mode); - } - } - } -} - -static inline int __fls(uint32_t word) -{ - int bit; - __asm__("bsrl %1,%0" - :"=r" (bit) - :"rm" (word)); - return word ? bit : -1; -} - -#if 0 -static __inline__ int find_highest_bit(unsigned long *data, int length){ - while(length && !data[--length]); - return __fls(data[length]) + 32 * length; -} -#endif -int -ioapic_get_highest_irq(IOAPICState *s){ - uint32_t irqs; - if (!s) - return -1; - irqs = s->irr & ~s->isr; - return __fls(irqs); -} - - -void -service_ioapic(IOAPICState *s){ - int irqno; - - while((irqno = ioapic_get_highest_irq(s)) != -1){ - IOAPIC_LOG("service_ioapic: highest irqno %x\n", irqno); - - if (!s->redirtbl[irqno].RedirForm.mask) - ioapic_deliver(s, irqno); - - if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){ - s->isr |= (1 << irqno); - } - // clear_bit(irqno, &s->irr); - s->irr &= ~(1 << irqno); - } -} - -void -ioapic_update_irq(IOAPICState *s) -{ - s->INTR = 1; -} - -void -ioapic_set_irq(IOAPICState *s, int irq, int level) -{ - IOAPIC_LOG("ioapic_set_irq %x %x\n", irq, level); - - /* Timer interrupt implemented on HV side */ - if(irq == 0x0) return; - if (!s){ - fprintf(logfile, "ioapic_set_irq null parameter\n"); - return; - } - if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask) - return; -#ifdef IOAPIC_DEBUG - ioapic_dump_redir(s, irq); -#endif - if (irq >= 0 && irq < IOAPIC_NUM_PINS){ - uint32_t bit = 1 << irq; - if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){ - if(level) - s->irr |= bit; - else - s->irr &= ~bit; - }else{ - if(level) - /* XXX No irr clear for edge interrupt */ - s->irr |= bit; - } - } - - ioapic_update_irq(s); -} - -void -ioapic_legacy_irq(int irq, int level) -{ - ioapic_set_irq(ioapic, irq, level); -} - -static inline int find_highest_bit(uint32_t *data, int length){ - while(length && !data[--length]); - return __fls(data[length]) + 32 * length; -} - -int -get_redir_num(IOAPICState *s, int vector){ - int i = 0; - if(!s){ - IOAPIC_ERR("Null parameter for get_redir_num\n"); - return -1; - } - for(; i < IOAPIC_NUM_PINS-1; i++){ - if (s->redirtbl[i].RedirForm.vector == vector) - return i; - } - return -1; -} - -void -ioapic_update_EOI() -{ - int i = 0; - uint32_t isr_info ; - uint32_t vector; - IOAPICState *s = ioapic; - - isr_info = s->isr; - - for (i = 0; i < s->lapic_count; i++){ - if (!s->lapic_info[i] || - !test_bit(VL_STATE_EOI, s->lapic_info[i]->vl_state)) - continue; - get_shareinfo_eoi(s->lapic_info[i]); - while((vector = find_highest_bit((unsigned int *)&s->lapic_info[i]->vl_eoi[0],VLAPIC_INT_COUNT_32)) != -1){ - int redir_num; - if ((redir_num = get_redir_num(s, vector)) == -1){ - IOAPIC_ERR("Can't find redir item for %d EOI \n", vector); - continue; - } - if (!test_and_clear_bit(redir_num, &s->isr)){ - IOAPIC_ERR("redir %d not set for %d EOI\n", redir_num, vector); - continue; - } - clear_bit(vector, &s->lapic_info[i]->vl_eoi[0]); - } - clear_bit(VL_STATE_EOI, &s->lapic_info[i]->vl_state); - put_shareinfo_eoi(s->lapic_info[i]); - } -} - - -void -ioapic_init_apic_info(IOAPICState *s) -{ -#ifdef IOAPIC_DEBUG - fprintf(logfile, "ioapic_init_apic_info\n"); - if (!s) - return; -#endif - -#if 0 - if (!vio || !(vio->vl_number)){ - fprintf(logfile, "null vio or o vl number\n"); - return; - } - - for (i = 0; i < MAX_LAPIC_NUM; i++) s->lapic_info[i] = NULL; - - s->lapic_count = vio->vl_number; - for (i = 0; i < vio->vl_number; i++) - s->lapic_info[i] = vio->vl_info + i; -#endif - -} - -void -ioapic_intack(IOAPICState *s) -{ -#ifdef IOAPIC_DEBUG - if (!s){ - fprintf(logfile, "ioapic_intack null parameter\n"); - return; - } -#endif - if (!s) s->INTR = 0; -} - -int -ioapic_has_intr() -{ - return ioapic->INTR; -} - -void -do_ioapic() -{ - service_ioapic(ioapic); - ioapic_intack(ioapic); -} - -IOAPICState * -IOAPICInit( ) -{ - IOAPICState *s; - - s = qemu_mallocz(sizeof(IOAPICState)); - if (!s){ - fprintf(logfile, "IOAPICInit: malloc failed\n"); - return NULL; - } - - IOAPICReset(s); - ioapic_init_apic_info(s); - register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); - /* Remove after GFW ready */ - ioapic_update_config(s, 0xfec00000, 1); - - ioapic = s; - return s; -} diff -r d51b071bfcfc -r 66dd96e90be4 tools/ioemu/hw/ioapic.h --- a/tools/ioemu/hw/ioapic.h Mon Nov 7 22:53:25 2005 +++ /dev/null Tue Nov 8 02:40:31 2005 @@ -1,128 +0,0 @@ -///////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2001 MandrakeSoft S.A. -// -// MandrakeSoft S.A. -// 43, rue d'Aboukir -// 75002 Paris - France -// http://www.linux-mandrake.com/ -// http://www.mandrakesoft.com/ -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - -#ifndef __IOAPIC_H -#define __IOAPIC_H - -#include <xenctrl.h> -#include <xen/io/ioreq.h> -#include <xen/io/vmx_vlapic.h> - -#define IOAPIC_NUM_PINS 24 -#define IOAPIC_VERSION_ID 0x11 -#define IOAPIC_LEVEL_TRIGGER 1 -#define APIC_DM_FIXED 0 -#define APIC_DM_LOWPRI 1 - - - -#ifdef CONFIG_SMP -#define LOCK_PREFIX "lock ; " -#else -#define LOCK_PREFIX "" -#endif - -#ifdef __I386__ -#define __OS "q" -#define __OP "r" -#else -#define __OS "l" /* Operation Suffix */ -#define __OP "e" /* Operand Prefix */ -#endif - -#define ADDR (*(volatile long *) addr) -#if 0 -#endif -extern void *shared_page; -extern FILE *logfile; -#ifdef __BIGENDIAN__ -typedef union RedirStatus -{ - uint64_t value; - struct { - uint8_t dest_id; - uint8_t reserved[4]; - uint8_t reserve:7; - uint8_t mask:1; /* interrupt mask*/ - uint8_t trigmod:1; - uint8_t remoteirr:1; - uint8_t polarity:1; - uint8_t delivestatus:1; - uint8_t destmode:1; - uint8_t deliver_mode:3; - uint8_t vector; - }RedirForm; -}RedirStatus; -#else -typedef union RedirStatus -{ - uint64_t value; - struct { - uint8_t vector; - uint8_t deliver_mode:3; - uint8_t destmode:1; - uint8_t delivestatus:1; - uint8_t polarity:1; - uint8_t remoteirr:1; - uint8_t trigmod:1; - uint8_t mask:1; /* interrupt mask*/ - uint8_t reserve:7; - uint8_t reserved[4]; - uint8_t dest_id; - }RedirForm; -}RedirStatus; -#endif -/* - * IOAPICState stands for a instance of a IOAPIC - */ - -/* FIXME tmp before working with Local APIC */ -#define IOAPIC_MEM_LENGTH 0x100 -#define IOAPIC_ENABLE_MASK 0x0 -#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK) -#define MAX_LAPIC_NUM 32 - -struct IOAPICState{ - uint32_t INTR; - uint32_t id; - uint32_t arb_id; - uint32_t flags; - unsigned long base_address; - uint32_t irr; - uint32_t isr; /* This is used for level trigger */ - uint8_t vector_irr[256]; - RedirStatus redirtbl[IOAPIC_NUM_PINS]; - uint32_t ioregsel; - uint32_t lapic_count; - vlapic_info *lapic_info[MAX_LAPIC_NUM]; -}; -#define IOAPIC_REG_APIC_ID 0x0 -#define IOAPIC_REG_VERSION 0x1 -#define IOAPIC_REG_ARB_ID 0x2 -#define IOAPICEnabled(s) (s->flags & IOAPIC_ENABLE_FLAG) - -typedef struct IOAPICState IOAPICState; - -#endif _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |