[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] This is a follow up of PIC device model by Xiaofeng and me to move to
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID 2d5b92e7c79a714640397b6c7d797a56aa230f8b # Parent 8eaaa622db81393ef0eae497090c34c04adf4212 This is a follow up of PIC device model by Xiaofeng and me to move to hypervisor using virtual weired interrupt line. With this patch the performance of CPU2K improves 7%, kernel kuild improves 14% and cyclesoak improves 12%. It is quite amazing! Signed-off-by: Xiaofeng Ling <xiaofeng.ling@xxxxxxxxx> Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx> diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/hw/i8254.c --- a/tools/ioemu/hw/i8254.c Fri Oct 21 17:19:38 2005 +++ b/tools/ioemu/hw/i8254.c Fri Oct 21 17:29:26 2005 @@ -222,9 +222,7 @@ int irq, i; PITChannelState *s; - /* Assumes PIT is wired to IRQ0 and -1 is uninitialized irq base */ - if ((irq = pic_irq2vec(0)) == -1) - return; + irq = 0; for(i = 0; i < 3; i++) { if (pit_state.channels[i].vmx_channel) diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/target-i386-dm/Makefile --- a/tools/ioemu/target-i386-dm/Makefile Fri Oct 21 17:19:38 2005 +++ b/tools/ioemu/target-i386-dm/Makefile Fri Oct 21 17:29:26 2005 @@ -271,7 +271,7 @@ # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o port-e9.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o VL_OBJS+= cirrus_vga.o pcnet.o ifeq ($(TARGET_ARCH), ppc) diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/target-i386-dm/helper2.c --- a/tools/ioemu/target-i386-dm/helper2.c Fri Oct 21 17:19:38 2005 +++ b/tools/ioemu/target-i386-dm/helper2.c Fri Oct 21 17:29:26 2005 @@ -404,20 +404,6 @@ } void -do_interrupt(CPUState *env, int vector) -{ - unsigned long *intr; - - // Send a message on the event channel. Add the vector to the shared mem - // page. - intr = (unsigned long *) &(shared_page->sp_global.pic_intr[0]); - atomic_set_bit(vector, intr); - if (loglevel & CPU_LOG_INT) - fprintf(logfile, "injecting vector: %x\n", vector); - env->send_event = 1; -} - -void destroy_vmx_domain(void) { extern FILE* logfile; @@ -429,7 +415,6 @@ int main_loop(void) { - int vector; fd_set rfds; struct timeval tv; extern CPUState *global_env; @@ -476,11 +461,6 @@ ioapic_update_EOI(); #endif cpu_timer_handler(env); - if (env->interrupt_request & CPU_INTERRUPT_HARD) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - vector = cpu_get_pic_interrupt(env); - do_interrupt(env, vector); - } #ifdef APIC_SUPPORT if (ioapic_has_intr()) do_ioapic(); diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/Makefile --- a/xen/arch/x86/Makefile Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/Makefile Fri Oct 21 17:29:26 2005 @@ -4,6 +4,7 @@ OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S)) OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard acpi/*.c)) +OBJS += $(patsubst %.c,%.o,$(wildcard dm/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard genapic/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard cpu/*.c)) @@ -66,6 +67,7 @@ rm -f x86_64/*.o x86_64/*~ x86_64/core rm -f mtrr/*.o mtrr/*~ mtrr/core rm -f acpi/*.o acpi/*~ acpi/core + rm -f dm/*.o dm/*~ dm/core rm -f genapic/*.o genapic/*~ genapic/core rm -f cpu/*.o cpu/*~ cpu/core diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/domain.c Fri Oct 21 17:29:26 2005 @@ -39,7 +39,6 @@ #include <asm/msr.h> #include <asm/physdev.h> #include <xen/kernel.h> -#include <public/io/ioreq.h> #include <xen/multicall.h> /* opt_noreboot: If true, machine will need manual reset on error. */ diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx.c --- a/xen/arch/x86/vmx.c Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/vmx.c Fri Oct 21 17:29:26 2005 @@ -647,8 +647,8 @@ p->u.data = value; if (vmx_portio_intercept(p)) { - /* no blocking & no evtchn notification */ - clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IORESP_READY; + vmx_io_assist(v); return; } diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_intercept.c --- a/xen/arch/x86/vmx_intercept.c Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/vmx_intercept.c Fri Oct 21 17:29:26 2005 @@ -209,8 +209,7 @@ missed_ticks = (NOW() - vpit->scheduled)/(s_time_t) vpit->period; /* Set the pending intr bit, and send evtchn notification to myself. */ - if (test_and_set_bit(vpit->vector, vpit->intr_bitmap)) - vpit->pending_intr_nr++; /* already set, then count the pending intr */ + vpit->pending_intr_nr++; /* already set, then count the pending intr */ evtchn_set_pending(vpit->v, iopacket_port(vpit->v->domain)); /* pick up missed timer tick */ @@ -230,11 +229,8 @@ { vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id); ioreq_t *p = &vio->vp_ioreq; - shared_iopage_t *sp = get_sp(v->domain); - u64 *intr = &(sp->sp_global.pic_intr[0]); struct vmx_virpit *vpit = &(v->domain->arch.vmx_platform.vmx_pit); int rw_mode, reinit = 0; - int oldvec = 0; /* load init count*/ if (p->state == STATE_IORESP_HOOK) { @@ -243,7 +239,7 @@ VMX_DBG_LOG(DBG_LEVEL_1, "VMX_PIT: guest reset PIT with channel %lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) ); rem_ac_timer(&(vpit->pit_timer)); reinit = 1; - oldvec = vpit->vector; + } else init_ac_timer(&vpit->pit_timer, pit_timer_fn, vpit, v->processor); @@ -257,12 +253,6 @@ printk("VMX_PIT: guest programmed too small an init_val: %x\n", vpit->init_val); vpit->period = 1000000; - } - vpit->vector = ((p->u.data >> 16) & 0xFF); - - if( reinit && oldvec != vpit->vector){ - clear_bit(oldvec, intr); - vpit->pending_intr_nr = 0; } vpit->channel = ((p->u.data >> 24) & 0x3); @@ -287,7 +277,6 @@ break; } - vpit->intr_bitmap = intr; vpit->v = v; vpit->scheduled = NOW() + vpit->period; @@ -297,8 +286,9 @@ p->state = STATE_IORESP_READY; /* register handler to intercept the PIT io when vm_exit */ - if (!reinit) + if (!reinit) { register_portio_handler(0x40, 4, intercept_pit_io); + } } } #endif /* CONFIG_VMX */ diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_io.c --- a/xen/arch/x86/vmx_io.c Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/vmx_io.c Fri Oct 21 17:29:26 2005 @@ -37,6 +37,7 @@ #include <asm/shadow.h> #include <public/io/ioreq.h> +#include <public/io/vmx_vpic.h> #include <public/io/vmx_vlapic.h> #ifdef CONFIG_VMX @@ -794,57 +795,6 @@ } #define BSP_CPU(v) (!(v->vcpu_id)) -static inline void clear_extint(struct vcpu *v) -{ - global_iodata_t *spg; - int i; - spg = &get_sp(v->domain)->sp_global; - - for(i = 0; i < INTR_LEN; i++) - spg->pic_intr[i] = 0; -} - -static inline void clear_highest_bit(struct vcpu *v, int vector) -{ - global_iodata_t *spg; - - spg = &get_sp(v->domain)->sp_global; - - clear_bit(vector, &spg->pic_intr[0]); -} - -static inline int find_highest_pic_irq(struct vcpu *v) -{ - u64 intr[INTR_LEN]; - global_iodata_t *spg; - int i; - - if(!BSP_CPU(v)) - return -1; - - spg = &get_sp(v->domain)->sp_global; - - for(i = 0; i < INTR_LEN; i++){ - intr[i] = spg->pic_intr[i] & ~spg->pic_mask[i]; - } - - return find_highest_irq((u32 *)&intr[0]); -} - -/* - * Return 0-255 for pending irq. - * -1 when no pending. - */ -static inline int find_highest_pending_irq(struct vcpu *v, int *type) -{ - int result = -1; - if ((result = find_highest_pic_irq(v)) != -1){ - *type = VLAPIC_DELIV_MODE_EXT; - return result; - } - return result; -} - static inline void interrupt_post_injection(struct vcpu * v, int vector, int type) { @@ -853,17 +803,17 @@ switch(type) { case VLAPIC_DELIV_MODE_EXT: - if (vpit->pending_intr_nr && vector == vpit->vector) - vpit->pending_intr_nr--; - else - clear_highest_bit(v, vector); - - if (vector == vpit->vector && !vpit->first_injected){ - vpit->first_injected = 1; - vpit->pending_intr_nr = 0; - } - if (vector == vpit->vector) + if ( is_pit_irq(v, vector) ) { + if ( !vpit->first_injected ) { + vpit->first_injected = 1; + vpit->pending_intr_nr = 0; + } + else { + vpit->pending_intr_nr--; + } vpit->inject_point = NOW(); + + } break; default: @@ -893,6 +843,38 @@ static inline int irq_masked(unsigned long eflags) { return ((eflags & X86_EFLAGS_IF) == 0); +} + +void pic_irq_request(int *interrupt_request, int level) +{ + if (level) + *interrupt_request = 1; + else + *interrupt_request = 0; +} + +void vmx_pic_assist(struct vcpu *v) +{ + global_iodata_t *spg; + u16 *virq_line, irqs; + struct vmx_virpic *pic = &v->domain->arch.vmx_platform.vmx_pic; + + spg = &get_sp(v->domain)->sp_global; + virq_line = &spg->pic_clear_irr; + if ( *virq_line ) { + do { + irqs = *(volatile u16*)virq_line; + } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs ); + do_pic_irqs_clear(pic, irqs); + } + virq_line = &spg->pic_irr; + if ( *virq_line ) { + do { + irqs = *(volatile u16*)virq_line; + } while ( (u16)cmpxchg(virq_line,irqs, 0) != irqs ); + do_pic_irqs(pic, irqs); + } + } asmlinkage void vmx_intr_assist(void) @@ -901,11 +883,18 @@ int highest_vector; unsigned long intr_fields, eflags, interruptibility, cpu_exec_control; struct vcpu *v = current; - - highest_vector = find_highest_pending_irq(v, &intr_type); + struct virtual_platform_def *plat=&v->domain->arch.vmx_platform; + struct vmx_virpit *vpit = &plat->vmx_pit; + struct vmx_virpic *pic= &plat->vmx_pic; + + vmx_pic_assist(v); __vmread_vcpu(v, CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control); - - if (highest_vector == -1) { + if ( vpit->pending_intr_nr ) { + pic_set_irq(pic, 0, 0); + pic_set_irq(pic, 0, 1); + } + + if ( !plat->interrupt_request ) { disable_irq_window(cpu_exec_control); return; } @@ -922,22 +911,20 @@ if (interruptibility) { enable_irq_window(cpu_exec_control); - VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, interruptibility: %lx", - highest_vector, interruptibility); + VMX_DBG_LOG(DBG_LEVEL_1, "interruptibility: %lx",interruptibility); return; } __vmread(GUEST_RFLAGS, &eflags); + if (irq_masked(eflags)) { + enable_irq_window(cpu_exec_control); + return; + } + plat->interrupt_request = 0; + highest_vector = cpu_get_pic_interrupt(v, &intr_type); switch (intr_type) { case VLAPIC_DELIV_MODE_EXT: - if (irq_masked(eflags)) { - enable_irq_window(cpu_exec_control); - VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx", - highest_vector, eflags); - return; - } - vmx_inject_extint(v, highest_vector, VMX_INVALID_ERROR_CODE); TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0); break; diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/vmx_vmcs.c --- a/xen/arch/x86/vmx_vmcs.c Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/vmx_vmcs.c Fri Oct 21 17:29:26 2005 @@ -210,8 +210,14 @@ static void vmx_setup_platform(struct vcpu *v) { - if (v->vcpu_id == 0) + struct virtual_platform_def *platform; + if (v->vcpu_id == 0) { get_io_shared_page(v); + platform = &v->domain->arch.vmx_platform; + pic_init(&platform->vmx_pic, pic_irq_request, + &platform->interrupt_request); + register_pic_io_hook(); + } } static void vmx_set_host_env(struct vcpu *v) @@ -275,7 +281,8 @@ page = (struct pfn_info *) alloc_domheap_page(NULL); pfn = (unsigned long) (page - frame_table); - vmx_setup_platform(v); + if ( v == v->domain->vcpu[0] ) + vmx_setup_platform(v); vmx_set_host_env(v); diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx.h --- a/xen/include/asm-x86/vmx.h Fri Oct 21 17:19:38 2005 +++ b/xen/include/asm-x86/vmx.h Fri Oct 21 17:29:26 2005 @@ -34,6 +34,7 @@ extern void vmx_asm_do_resume(void); extern void vmx_asm_do_launch(void); extern void vmx_intr_assist(void); +extern void pic_irq_request(int *interrupt_request, int level); extern void arch_vmx_do_launch(struct vcpu *); extern void arch_vmx_do_resume(struct vcpu *); diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_intercept.h --- a/xen/include/asm-x86/vmx_intercept.h Fri Oct 21 17:19:38 2005 +++ b/xen/include/asm-x86/vmx_intercept.h Fri Oct 21 17:29:26 2005 @@ -8,7 +8,7 @@ #include <xen/errno.h> #include <public/io/ioreq.h> -#define MAX_IO_HANDLER 4 +#define MAX_IO_HANDLER 8 #define VMX_PORTIO 0 #define VMX_MMIO 1 diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_platform.h --- a/xen/include/asm-x86/vmx_platform.h Fri Oct 21 17:19:38 2005 +++ b/xen/include/asm-x86/vmx_platform.h Fri Oct 21 17:29:26 2005 @@ -24,6 +24,7 @@ #include <asm/e820.h> #include <asm/vmx_virpit.h> #include <asm/vmx_intercept.h> +#include <public/io/vmx_vpic.h> #define MAX_OPERAND_NUM 2 @@ -80,6 +81,8 @@ unsigned long shared_page_va; struct vmx_virpit vmx_pit; struct vmx_io_handler vmx_io_handler; + struct vmx_virpic vmx_pic; + int interrupt_request; }; extern void handle_mmio(unsigned long, unsigned long); diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/asm-x86/vmx_virpit.h --- a/xen/include/asm-x86/vmx_virpit.h Fri Oct 21 17:19:38 2005 +++ b/xen/include/asm-x86/vmx_virpit.h Fri Oct 21 17:29:26 2005 @@ -18,13 +18,11 @@ struct vmx_virpit { /* for simulation of counter 0 in mode 2*/ - int vector; /* the pit irq vector */ - unsigned int period; /* the frequency. e.g. 10ms*/ + u32 period; /* pit frequency in ns */ s_time_t scheduled; /* scheduled timer interrupt */ unsigned int channel; /* the pit channel, counter 0~2 */ - u64 *intr_bitmap; unsigned int pending_intr_nr; /* the couner for pending timer interrupts */ - unsigned long long inject_point; /* the time inject virt intr */ + u64 inject_point; /* the time inject virt intr */ struct ac_timer pit_timer; /* periodic timer for mode 2*/ int first_injected; /* flag to prevent shadow window */ diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/public/io/ioreq.h --- a/xen/include/public/io/ioreq.h Fri Oct 21 17:19:38 2005 +++ b/xen/include/public/io/ioreq.h Fri Oct 21 17:29:26 2005 @@ -60,8 +60,10 @@ #define INTR_LEN (MAX_VECTOR/(BITS_PER_BYTE * sizeof(uint64_t))) typedef struct { - uint64_t pic_intr[INTR_LEN]; - uint64_t pic_mask[INTR_LEN]; + uint16_t pic_elcr; + uint16_t pic_irr; + uint16_t pic_last_irr; + uint16_t pic_clear_irr; int eport; /* Event channel port */ } global_iodata_t; diff -r 8eaaa622db81 -r 2d5b92e7c79a tools/ioemu/hw/i8259_stub.c --- /dev/null Fri Oct 21 17:19:38 2005 +++ b/tools/ioemu/hw/i8259_stub.c Fri Oct 21 17:29:26 2005 @@ -0,0 +1,96 @@ +/* Xen 8259 stub for interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2005 Intel corperation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "xenctrl.h" +#include <xen/io/ioreq.h> +#include <stdio.h> +#include "cpu.h" +#include "cpu-all.h" + +static __inline__ void atomic_set_bit(long nr, volatile void *addr) +{ + __asm__ __volatile__( + "lock ; bts %1,%0" + :"=m" (*(volatile long *)addr) + :"dIr" (nr)); +} +static __inline__ void atomic_clear_bit(long nr, volatile void *addr) +{ + __asm__ __volatile__( + "lock ; btr %1,%0" + :"=m" (*(volatile long *)addr) + :"dIr" (nr)); +} + +#include <vl.h> +extern shared_iopage_t *shared_page; +extern CPUState *global_env; +void pic_set_irq(int irq, int level) +{ + global_iodata_t *gio; + int mask; + + gio = &shared_page->sp_global; + mask = 1 << irq; + if ( gio->pic_elcr & mask ) { + /* level */ + if ( level ) { + atomic_set_bit(irq, &gio->pic_irr); + atomic_clear_bit(irq, &gio->pic_clear_irr); + global_env->send_event = 1; + } + else { + atomic_set_bit(irq, &gio->pic_clear_irr); + atomic_clear_bit(irq, &gio->pic_irr); + global_env->send_event = 1; + } + } + else { + /* edge */ + if ( level ) { + if ( (mask & gio->pic_last_irr) == 0 ) { + atomic_set_bit(irq, &gio->pic_irr); + atomic_set_bit(irq, &gio->pic_last_irr); + global_env->send_event = 1; + } + } + else { + atomic_clear_bit(irq, &gio->pic_last_irr); + } + } +} + +void irq_info(void) +{ + term_printf("irq statistic code not compiled.\n"); +} + +void pic_info(void) +{ + term_printf("pic_infoi code not compiled.\n"); +} + +void pic_init(void) +{ +} + diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/arch/x86/dm/i8259.c --- /dev/null Fri Oct 21 17:19:38 2005 +++ b/xen/arch/x86/dm/i8259.c Fri Oct 21 17:29:26 2005 @@ -0,0 +1,520 @@ +/* + * QEMU 8259 interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2005 Intel Corperation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#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 <public/io/vmx_vlapic.h> +#include <asm/current.h> + +/* set irq level. If an edge is detected, then the IRR is set to 1 */ +static inline void pic_set_irq1(PicState *s, int irq, int level) +{ + int mask; + mask = 1 << irq; + if (s->elcr & mask) { + /* level triggered */ + if (level) { + s->irr |= mask; + s->last_irr |= mask; + } else { + s->irr &= ~mask; + s->last_irr &= ~mask; + } + } else { + /* edge triggered */ + if (level) { + if ((s->last_irr & mask) == 0) { + s->irr |= mask; + } + s->last_irr |= mask; + } else { + s->last_irr &= ~mask; + } + } +} + +/* return the highest priority found in mask (highest = smallest + number). Return 8 if no irq */ +static inline int get_priority(PicState *s, int mask) +{ + int priority; + if (mask == 0) + return 8; + priority = 0; + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) + priority++; + return priority; +} + +/* return the pic wanted interrupt. return -1 if none */ +static int pic_get_irq(PicState *s) +{ + int mask, cur_priority, priority; + + mask = s->irr & ~s->imr; + priority = get_priority(s, mask); + if (priority == 8) + return -1; + /* compute current priority. If special fully nested mode on the + master, the IRQ coming from the slave is not taken into account + for the priority computation. */ + mask = s->isr; + if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) + mask &= ~(1 << 2); + cur_priority = get_priority(s, mask); + if (priority < cur_priority) { + /* higher priority found: an irq should be generated */ + return (priority + s->priority_add) & 7; + } else { + return -1; + } +} + +/* raise irq to CPU if necessary. must be called every time the active + irq may change */ +/* XXX: should not export it, but it is needed for an APIC kludge */ +void pic_update_irq(struct vmx_virpic *s) +{ + int irq2, irq; + + /* first look at slave pic */ + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) { + /* if irq request by slave pic, signal master PIC */ + pic_set_irq1(&s->pics[0], 2, 1); + pic_set_irq1(&s->pics[0], 2, 0); + } + /* look at requested irq */ + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) { + s->irq_request(s->irq_request_opaque, 1); + } +} + +void pic_set_irq_new(void *opaque, int irq, int level) +{ + struct vmx_virpic *s = opaque; + + pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); + /* used for IOAPIC irqs */ + if (s->alt_irq_func) + s->alt_irq_func(s->alt_irq_opaque, irq, level); + pic_update_irq(s); +} + +void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs) +{ + s->pics[1].irr |= (uint8_t)(irqs >> 8); + s->pics[0].irr |= (uint8_t) irqs; + /* TODO for alt_irq_func */ + pic_update_irq(s); +} + +void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs) +{ + s->pics[1].irr &= ~(uint8_t)(irqs >> 8); + s->pics[0].irr &= ~(uint8_t) irqs; + pic_update_irq(s); +} + +/* obsolete function */ +void pic_set_irq(struct vmx_virpic *isa_pic, int irq, int level) +{ + pic_set_irq_new(isa_pic, irq, level); +} + +/* acknowledge interrupt 'irq' */ +static inline void pic_intack(PicState *s, int irq) +{ + if (s->auto_eoi) { + if (s->rotate_on_auto_eoi) + s->priority_add = (irq + 1) & 7; + } else { + s->isr |= (1 << irq); + } + /* We don't clear a level sensitive interrupt here */ + if (!(s->elcr & (1 << irq))) + s->irr &= ~(1 << irq); +} + +int pic_read_irq(struct vmx_virpic *s) +{ + int irq, irq2, intno; + + irq = pic_get_irq(&s->pics[0]); + if (irq >= 0) { + pic_intack(&s->pics[0], irq); + if (irq == 2) { + irq2 = pic_get_irq(&s->pics[1]); + if (irq2 >= 0) { + pic_intack(&s->pics[1], irq2); + } else { + /* spurious IRQ on slave controller */ + irq2 = 7; + } + intno = s->pics[1].irq_base + irq2; + irq = irq2 + 8; + } else { + intno = s->pics[0].irq_base + irq; + } + } else { + /* spurious IRQ on host controller */ + printk("spurious IRQ irq got=%d\n",irq); + irq = 7; + intno = s->pics[0].irq_base + irq; + } + pic_update_irq(s); + + return intno; +} + +static void update_shared_irr(struct vmx_virpic *s, PicState *c) +{ + uint8_t *pl, *pe; + + get_sp(current->domain)->sp_global.pic_elcr = + s->pics[0].elcr | ((u16)s->pics[1].elcr << 8); + pl =(uint8_t*)&get_sp(current->domain)->sp_global.pic_last_irr; + pe =(uint8_t*)&get_sp(current->domain)->sp_global.pic_elcr; + if ( c == &s->pics[0] ) { + *pl = c->last_irr; + *pe = c->elcr; + } + else { + *(pl+1) = c->last_irr; + *(pe+1) = c->elcr; + } +} + +static void pic_reset(void *opaque) +{ + PicState *s = opaque; + + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; + s->elcr = 0; +} + +static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PicState *s = opaque; + int priority, cmd, irq; + + addr &= 1; + if (addr == 0) { + if (val & 0x10) { + /* init */ + pic_reset(s); + update_shared_irr(s->pics_state, s); + /* deassert a pending interrupt */ + s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0); + s->init_state = 1; + s->init4 = val & 1; + if (val & 0x02) + hw_error("single mode not supported"); + if (val & 0x08) + hw_error("level sensitive irq not supported"); + } else if (val & 0x08) { + if (val & 0x04) + s->poll = 1; + if (val & 0x02) + s->read_reg_select = val & 1; + if (val & 0x40) + s->special_mask = (val >> 5) & 1; + } else { + cmd = val >> 5; + switch(cmd) { + case 0: + case 4: + s->rotate_on_auto_eoi = cmd >> 2; + break; + case 1: /* end of interrupt */ + case 5: + priority = get_priority(s, s->isr); + if (priority != 8) { + irq = (priority + s->priority_add) & 7; + s->isr &= ~(1 << irq); + if (cmd == 5) + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + } + break; + case 3: + irq = val & 7; + s->isr &= ~(1 << irq); + pic_update_irq(s->pics_state); + break; + case 6: + s->priority_add = (val + 1) & 7; + pic_update_irq(s->pics_state); + break; + case 7: + irq = val & 7; + s->isr &= ~(1 << irq); + s->priority_add = (irq + 1) & 7; + pic_update_irq(s->pics_state); + break; + default: + /* no operation */ + break; + } + } + } else { + switch(s->init_state) { + case 0: + /* normal mode */ + s->imr = val; + pic_update_irq(s->pics_state); + break; + case 1: + s->irq_base = val & 0xf8; + s->init_state = 2; + break; + case 2: + if (s->init4) { + s->init_state = 3; + } else { + s->init_state = 0; + } + break; + case 3: + s->special_fully_nested_mode = (val >> 4) & 1; + s->auto_eoi = (val >> 1) & 1; + s->init_state = 0; + break; + } + } +} + +static uint32_t pic_poll_read (PicState *s, uint32_t addr1) +{ + int ret; + + ret = pic_get_irq(s); + if (ret >= 0) { + if (addr1 >> 7) { + s->pics_state->pics[0].isr &= ~(1 << 2); + s->pics_state->pics[0].irr &= ~(1 << 2); + } + s->irr &= ~(1 << ret); + s->isr &= ~(1 << ret); + if (addr1 >> 7 || ret != 2) + pic_update_irq(s->pics_state); + } else { + ret = 0x07; + pic_update_irq(s->pics_state); + } + + return ret; +} + +static uint32_t pic_ioport_read(void *opaque, uint32_t addr1) +{ + PicState *s = opaque; + unsigned int addr; + int ret; + + addr = addr1; + addr &= 1; + if (s->poll) { + ret = pic_poll_read(s, addr1); + s->poll = 0; + } else { + if (addr == 0) { + if (s->read_reg_select) + ret = s->isr; + else + ret = s->irr; + } else { + ret = s->imr; + } + } + return ret; +} + +/* memory mapped interrupt status */ +/* XXX: may be the same than pic_read_irq() */ +uint32_t pic_intack_read(struct vmx_virpic *s) +{ + int ret; + + ret = pic_poll_read(&s->pics[0], 0x00); + if (ret == 2) + ret = pic_poll_read(&s->pics[1], 0x80) + 8; + /* Prepare for ISR read */ + s->pics[0].read_reg_select = 1; + + return ret; +} + +static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + PicState *s = opaque; + s->elcr = val & s->elcr_mask; +} + +static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) +{ + PicState *s = opaque; + return s->elcr; +} + +/* XXX: add generic master/slave system */ +static void pic_init1(int io_addr, int elcr_addr, PicState *s) +{ + pic_reset(s); +} + +void pic_init(struct vmx_virpic *s, void (*irq_request)(), + void *irq_request_opaque) +{ + memset(s, 0, sizeof(*s)); + pic_init1(0x20, 0x4d0, &s->pics[0]); + pic_init1(0xa0, 0x4d1, &s->pics[1]); + s->pics[0].elcr_mask = 0xf8; + s->pics[1].elcr_mask = 0xde; + s->irq_request = irq_request; + s->irq_request_opaque = irq_request_opaque; + s->pics[0].pics_state = s; + s->pics[1].pics_state = s; + return; +} + +void pic_set_alt_irq_func(struct vmx_virpic *s, void (*alt_irq_func)(), + void *alt_irq_opaque) +{ + s->alt_irq_func = alt_irq_func; + s->alt_irq_opaque = alt_irq_opaque; +} + +static int intercept_pic_io(ioreq_t *p) +{ + struct vmx_virpic *pic; + struct vcpu *v = current; + uint32_t data; + + if ( p->size != 1 || p->count != 1) { + printk("PIC_IO wrong access size %d!\n", (int)p->size); + return 1; + } + pic = &v->domain->arch.vmx_platform.vmx_pic; + if ( p->dir == 0 ) { + if(p->pdata_valid) + vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_IN); + else + data = p->u.data; + pic_ioport_write((void*)&pic->pics[p->addr>>7], + (uint32_t) p->addr, (uint32_t) (data & 0xff)); + } + else { + data = pic_ioport_read( + (void*)&pic->pics[p->addr>>7], (uint32_t) p->addr); + if(p->pdata_valid) + vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_OUT); + else + p->u.data = (u64)data; + } + return 1; +} + +static int intercept_elcr_io(ioreq_t *p) +{ + struct vmx_virpic *s; + struct vcpu *v = current; + uint32_t data; + + if ( p->size != 1 || p->count != 1 ) { + printk("PIC_IO wrong access size %d!\n", (int)p->size); + return 1; + } + + s = &v->domain->arch.vmx_platform.vmx_pic; + if ( p->dir == 0 ) { + if(p->pdata_valid) + vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_IN); + else + data = p->u.data; + elcr_ioport_write((void*)&s->pics[p->addr&1], + (uint32_t) p->addr, (uint32_t)( data & 0xff)); + get_sp(current->domain)->sp_global.pic_elcr = + s->pics[0].elcr | ((u16)s->pics[1].elcr << 8); + } + else { + data = (u64) elcr_ioport_read( + (void*)&s->pics[p->addr&1], (uint32_t) p->addr); + if(p->pdata_valid) + vmx_copy(&data, (unsigned long)p->u.pdata, p->size, VMX_COPY_OUT); + else + p->u.data = (u64)data; + + } + return 1; +} +void register_pic_io_hook (void) +{ + register_portio_handler(0x20, 2, intercept_pic_io); + register_portio_handler(0x4d0, 1, intercept_elcr_io); + register_portio_handler(0xa0, 2, intercept_pic_io); + register_portio_handler(0x4d1, 1, intercept_elcr_io); +} + + +/* IRQ handling */ +int cpu_get_pic_interrupt(struct vcpu *v, int *type) +{ + int intno; + struct vmx_virpic *s = &v->domain->arch.vmx_platform.vmx_pic; + + /* read the irq from the PIC */ + intno = pic_read_irq(s); + *type = VLAPIC_DELIV_MODE_EXT; + return intno; +} + +int is_pit_irq(struct vcpu *v, int irq) +{ + int pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base; + + return (irq == pit_vec); +} diff -r 8eaaa622db81 -r 2d5b92e7c79a xen/include/public/io/vmx_vpic.h --- /dev/null Fri Oct 21 17:19:38 2005 +++ b/xen/include/public/io/vmx_vpic.h Fri Oct 21 17:29:26 2005 @@ -0,0 +1,84 @@ +/* + * QEMU System Emulator header + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2005 Intel Corp + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _VMX_VPIC_H +#define _VMX_VPIC_H + +#define hw_error(x) do {} while (0); + + +/* i8259.c */ +typedef struct IOAPICState IOAPICState; +typedef struct PicState { + uint8_t last_irr; /* edge detection */ + uint8_t irr; /* interrupt request register */ + uint8_t imr; /* interrupt mask register */ + uint8_t isr; /* interrupt service register */ + uint8_t priority_add; /* highest irq priority */ + uint8_t irq_base; + uint8_t read_reg_select; + uint8_t poll; + uint8_t special_mask; + uint8_t init_state; + uint8_t auto_eoi; + uint8_t rotate_on_auto_eoi; + uint8_t special_fully_nested_mode; + uint8_t init4; /* true if 4 byte init */ + uint8_t elcr; /* PIIX edge/trigger selection*/ + uint8_t elcr_mask; + struct vmx_virpic *pics_state; +} PicState; + +struct vmx_virpic { + /* 0 is master pic, 1 is slave pic */ + /* XXX: better separation between the two pics */ + PicState pics[2]; + void (*irq_request)(int *opaque, int level); + void *irq_request_opaque; + /* IOAPIC callback support */ + void (*alt_irq_func)(void *opaque, int irq_num, int level); + void *alt_irq_opaque; +}; + + +void pic_set_irq(struct vmx_virpic *s, int irq, int level); +void pic_set_irq_new(void *opaque, int irq, int level); +void pic_init(struct vmx_virpic *s, + void (*irq_request)(), + void *irq_request_opaque); +void pic_set_alt_irq_func(struct vmx_virpic *s, + void(*alt_irq_func)(), + void *alt_irq_opaque); +int pic_read_irq(struct vmx_virpic *s); +void pic_update_irq(struct vmx_virpic *s); +uint32_t pic_intack_read(struct vmx_virpic *s); +void register_pic_io_hook (void); +int cpu_get_pic_interrupt(struct vcpu *v, int *type); +int is_pit_irq(struct vcpu *v, int irq); +void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs); +void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs); + +/* APIC */ +#endif /* _VMX_VPIC_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |