Index: kvm/qemu/vl.h =================================================================== --- kvm.orig/qemu/vl.h +++ kvm/qemu/vl.h @@ -1040,16 +1040,11 @@ ParallelState *parallel_init(int base, i /* i8259.c */ -typedef struct PicState2 PicState2; -extern PicState2 *isa_pic; -void pic_set_irq(int irq, int level); -void pic_set_irq_new(void *opaque, int irq, int level); -PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); -void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, - void *alt_irq_opaque); -int pic_read_irq(PicState2 *s); -void pic_update_irq(PicState2 *s); -uint32_t pic_intack_read(PicState2 *s); +#include "pic.h" + +PIC *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque); +void pic_set_alt_irq_func(PIC *pic, SetIRQFunc *alt_irq_func, + void *alt_irq_opaque); void pic_info(void); void irq_info(void); @@ -1057,7 +1052,6 @@ void irq_info(void); typedef struct IOAPICState IOAPICState; int apic_init(CPUState *env); -int apic_get_interrupt(CPUState *env); IOAPICState *ioapic_init(void); void ioapic_set_irq(void *opaque, int vector, int level); Index: kvm/qemu/hw/i8259.c =================================================================== --- kvm.orig/qemu/hw/i8259.c +++ kvm/qemu/hw/i8259.c @@ -29,6 +29,8 @@ //#define DEBUG_IRQ_LATENCY //#define DEBUG_IRQ_COUNT +typedef struct PicState2 PicState2; + typedef struct PicState { uint8_t last_irr; /* edge detection */ uint8_t irr; /* interrupt request register */ @@ -58,6 +60,7 @@ struct PicState2 { /* IOAPIC callback support */ SetIRQFunc *alt_irq_func; void *alt_irq_opaque; + PIC *base; }; #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT) @@ -133,8 +136,9 @@ static int pic_get_irq(PicState *s) /* 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(PicState2 *s) +static void i8259_update_irq(PIC *pic) { + PicState2 *s = (PicState2*)pic->private; int irq2, irq; /* first look at slave pic */ @@ -174,9 +178,9 @@ void pic_update_irq(PicState2 *s) int64_t irq_time[16]; #endif -void pic_set_irq_new(void *opaque, int irq, int level) +static void i8259_set_irq(PIC *pic, int irq, int level) { - PicState2 *s = opaque; + PicState2 *s = (PicState2*)pic->private; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq]) { @@ -199,13 +203,7 @@ void pic_set_irq_new(void *opaque, int i /* used for IOAPIC irqs */ if (s->alt_irq_func) s->alt_irq_func(s->alt_irq_opaque, irq, level); - pic_update_irq(s); -} - -/* obsolete function */ -void pic_set_irq(int irq, int level) -{ - pic_set_irq_new(isa_pic, irq, level); + pic_update_irq(pic); } /* acknowledge interrupt 'irq' */ @@ -231,8 +229,9 @@ static inline void pic_intack(PicState * } } -int pic_read_irq(PicState2 *s) +static int i8259_read_irq(PIC *pic) { + PicState2 *s = (PicState2*)pic->private; int irq, irq2, intno; irq = pic_get_irq(&s->pics[0]); @@ -256,7 +255,7 @@ int pic_read_irq(PicState2 *s) irq = 7; intno = s->pics[0].irq_base + irq; } - pic_update_irq(s); + pic_update_irq(pic); #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", @@ -333,23 +332,23 @@ static void pic_ioport_write(void *opaqu s->isr &= ~(1 << irq); if (cmd == 5) s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); } break; case 3: irq = val & 7; s->isr &= ~(1 << irq); - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); break; case 6: s->priority_add = (val + 1) & 7; - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); break; case 7: irq = val & 7; s->isr &= ~(1 << irq); s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); break; default: /* no operation */ @@ -361,7 +360,7 @@ static void pic_ioport_write(void *opaqu case 0: /* normal mode */ s->imr = val; - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); break; case 1: s->irq_base = val & 0xf8; @@ -396,10 +395,10 @@ static uint32_t pic_poll_read (PicState s->irr &= ~(1 << ret); s->isr &= ~(1 << ret); if (addr1 >> 7 || ret != 2) - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); } else { ret = 0x07; - pic_update_irq(s->pics_state); + pic_update_irq(s->pics_state->base); } return ret; @@ -434,8 +433,9 @@ static uint32_t pic_ioport_read(void *op /* memory mapped interrupt status */ /* XXX: may be the same than pic_read_irq() */ -uint32_t pic_intack_read(PicState2 *s) +static uint32_t i8259_intack_read(PIC *pic) { + PicState2 *s = (PicState2*)pic->private; int ret; ret = pic_poll_read(&s->pics[0], 0x00); @@ -518,16 +518,14 @@ static void pic_init1(int io_addr, int e qemu_register_reset(pic_reset, s); } -void pic_info(void) +static void i8259_info(PIC *pic) { int i; + PicState2 *s2 = (PicState2*)pic->private; PicState *s; - if (!isa_pic) - return; - for(i=0;i<2;i++) { - s = &isa_pic->pics[i]; + s = &s2->pics[i]; term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", i, s->irr, s->imr, s->isr, s->priority_add, s->irq_base, s->read_reg_select, s->elcr, @@ -535,7 +533,7 @@ void pic_info(void) } } -void irq_info(void) +static void i8259_stat(PIC *pic) { #ifndef DEBUG_IRQ_COUNT term_printf("irq statistic code not compiled.\n"); @@ -552,12 +550,38 @@ void irq_info(void) #endif } -PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) +void pic_info(void) { - PicState2 *s; - s = qemu_mallocz(sizeof(PicState2)); - if (!s) + isa_pic->info(isa_pic); +} + +void irq_info(void) +{ + isa_pic->stat(isa_pic); +} + +PIC *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) +{ + PIC *pic = qemu_mallocz(sizeof(PIC)); + if (!pic) + return NULL; + + pic->set = i8259_set_irq; + pic->read = i8259_read_irq; + pic->intack_read = i8259_intack_read; + pic->update = i8259_update_irq; + pic->info = i8259_info; + pic->stat = i8259_stat; + + pic->private = qemu_mallocz(sizeof(PicState2)); + if (!pic->private) { + qemu_free(pic); return NULL; + } + + PicState2 *s = (PicState2*)pic->private; + + s->base = pic; pic_init1(0x20, 0x4d0, &s->pics[0]); pic_init1(0xa0, 0x4d1, &s->pics[1]); s->pics[0].elcr_mask = 0xf8; @@ -566,12 +590,14 @@ PicState2 *pic_init(IRQRequestFunc *irq_ s->irq_request_opaque = irq_request_opaque; s->pics[0].pics_state = s; s->pics[1].pics_state = s; - return s; + return pic; } -void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, +void pic_set_alt_irq_func(PIC *pic, SetIRQFunc *alt_irq_func, void *alt_irq_opaque) { + PicState2 *s = (PicState2*)pic->private; + s->alt_irq_func = alt_irq_func; s->alt_irq_opaque = alt_irq_opaque; } Index: kvm/qemu/hw/ide.c =================================================================== --- kvm.orig/qemu/hw/ide.c +++ kvm/qemu/hw/ide.c @@ -2190,7 +2190,7 @@ void isa_ide_init(int iobase, int iobase if (!ide_state) return; - ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq); + ide_init2(ide_state, hd0, hd1, (SetIRQFunc *)isa_pic->set, isa_pic, irq); ide_init_ioport(ide_state, iobase, iobase2); } @@ -2617,9 +2617,9 @@ void pci_piix_ide_init(PCIBus *bus, Bloc PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, isa_pic, 14); + (SetIRQFunc *)isa_pic->set, isa_pic, 14); ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, isa_pic, 15); + (SetIRQFunc *)isa_pic->set, isa_pic, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); @@ -2656,9 +2656,9 @@ void pci_piix3_ide_init(PCIBus *bus, Blo PCI_ADDRESS_SPACE_IO, bmdma_map); ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, isa_pic, 14); + (SetIRQFunc *)isa_pic->set, isa_pic, 14); ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, isa_pic, 15); + (SetIRQFunc *)isa_pic->set, isa_pic, 15); ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); ide_init_ioport(&d->ide_if[2], 0x170, 0x376); Index: kvm/qemu/hw/pc.c =================================================================== --- kvm.orig/qemu/hw/pc.c +++ kvm/qemu/hw/pc.c @@ -89,18 +89,7 @@ void cpu_smm_update(CPUState *env) /* IRQ handling */ int cpu_get_pic_interrupt(CPUState *env) { - int intno; - - intno = apic_get_interrupt(env); - if (intno >= 0) { - /* set irq request if a PIC irq is still pending */ - /* XXX: improve that */ - pic_update_irq(isa_pic); - return intno; - } - /* read the irq from the PIC */ - intno = pic_read_irq(isa_pic); - return intno; + return apic_read_irq(env); } static void pic_irq_request(void *opaque, int level) @@ -679,7 +668,7 @@ static void pc_init1(int ram_size, int v for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_init(&pic_set_irq_new, isa_pic, + serial_init((SetIRQFunc *)isa_pic->set, isa_pic, serial_io[i], serial_irq[i], serial_hds[i]); } } Index: kvm/qemu/vl.c =================================================================== --- kvm.orig/qemu/vl.c +++ kvm/qemu/vl.c @@ -186,7 +186,7 @@ int time_drift_fix = 1; /* x86 ISA bus support */ target_phys_addr_t isa_mem_base = 0; -PicState2 *isa_pic; +PIC *isa_pic; uint32_t default_ioport_readb(void *opaque, uint32_t address) { Index: kvm/qemu/hw/apic.c =================================================================== --- kvm.orig/qemu/hw/apic.c +++ kvm/qemu/hw/apic.c @@ -84,6 +84,7 @@ typedef struct APICState { uint32_t initial_count; int64_t initial_count_load_time, next_time; QEMUTimer *timer; + CPUState *env; } APICState; struct IOAPICState { @@ -235,9 +236,9 @@ static void apic_bus_deliver(const uint3 apic_set_irq(apic_iter, vector_num, trigger_mode) ); } -void cpu_set_apic_base(CPUState *env, uint64_t val) +static void _apic_set_base(APIC *apic, uint64_t val) { - APICState *s = env->apic_state; + APICState *s = (APICState*)apic->private; #ifdef DEBUG_APIC printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif @@ -246,30 +247,30 @@ void cpu_set_apic_base(CPUState *env, ui /* if disabled, cannot be enabled again */ if (!(val & MSR_IA32_APICBASE_ENABLE)) { s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; - env->cpuid_features &= ~CPUID_APIC; + s->env->cpuid_features &= ~CPUID_APIC; s->spurious_vec &= ~APIC_SV_ENABLE; } } -uint64_t cpu_get_apic_base(CPUState *env) +static uint64_t _apic_get_base(APIC *apic) { - APICState *s = env->apic_state; + APICState *s = (APICState*)apic->private; #ifdef DEBUG_APIC printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); #endif return s->apicbase; } -void cpu_set_apic_tpr(CPUX86State *env, uint8_t val) +static void _apic_set_tpr(APIC *apic, uint8_t val) { - APICState *s = env->apic_state; + APICState *s = (APICState*)apic->private; s->tpr = (val & 0x0f) << 4; apic_update_irq(s); } -uint8_t cpu_get_apic_tpr(CPUX86State *env) +static uint8_t _apic_get_tpr(APIC *apic) { - APICState *s = env->apic_state; + APICState *s = (APICState*)apic->private; return s->tpr >> 4; } @@ -460,28 +461,34 @@ static void apic_deliver(APICState *s, u trigger_mode); } -int apic_get_interrupt(CPUState *env) +static int _apic_read_irq(APIC *apic) { - APICState *s = env->apic_state; + APICState *s = (APICState*)apic->private; int intno; /* if the APIC is installed or enabled, we let the 8259 handle the IRQs */ - if (!s) - return -1; - if (!(s->spurious_vec & APIC_SV_ENABLE)) - return -1; + if (!s || !(s->spurious_vec & APIC_SV_ENABLE)) + goto use_pic; /* XXX: spurious IRQ handling */ intno = get_highest_priority_int(s->irr); if (intno < 0) - return -1; + goto use_pic; if (s->tpr && intno <= s->tpr) return s->spurious_vec & 0xff; reset_bit(s->irr, intno); set_bit(s->isr, intno); apic_update_irq(s); + + /* set irq request if a PIC irq is still pending */ + /* XXX: improve that */ + pic_update_irq(isa_pic); + return intno; + + use_pic: + return pic_read_irq(isa_pic); } static uint32_t apic_get_current_count(APICState *s) @@ -563,7 +570,7 @@ static uint32_t apic_mem_readl(void *opa env = cpu_single_env; if (!env) return 0; - s = env->apic_state; + s = (APICState*)((APIC*)(env->apic))->private; index = (addr >> 4) & 0xff; switch(index) { @@ -640,7 +647,7 @@ static void apic_mem_writel(void *opaque env = cpu_single_env; if (!env) return; - s = env->apic_state; + s = (APICState*)((APIC*)(env->apic))->private; #ifdef DEBUG_APIC printf("APIC write: %08x = %08x\n", (uint32_t)addr, val); @@ -806,14 +813,31 @@ static CPUWriteMemoryFunc *apic_mem_writ int apic_init(CPUState *env) { + APIC *apic; APICState *s; if (last_apic_id >= MAX_APICS) return -1; + + apic = qemu_mallocz(sizeof(APIC)); + if(!apic) + return -1; + s = qemu_mallocz(sizeof(APICState)); - if (!s) + if (!s) { + qemu_free(apic); return -1; - env->apic_state = s; + } + env->apic = apic; + s->env = env; + + apic->read_irq = _apic_read_irq; + apic->set_base = _apic_set_base; + apic->get_base = _apic_get_base; + apic->set_tpr = _apic_set_tpr; + apic->get_tpr = _apic_get_tpr; + + apic->private = s; apic_init_ipi(s); s->id = last_apic_id++; s->cpu_env = env; Index: kvm/qemu/target-i386/cpu.h =================================================================== --- kvm.orig/qemu/target-i386/cpu.h +++ kvm/qemu/target-i386/cpu.h @@ -553,7 +553,7 @@ typedef struct CPUX86State { /* in order to simplify APIC support, we leave this pointer to the user */ - struct APICState *apic_state; + void *apic; } CPUX86State; CPUX86State *cpu_x86_init(void); @@ -651,12 +651,6 @@ void cpu_x86_set_a20(CPUX86State *env, i uint64_t cpu_get_tsc(CPUX86State *env); -void cpu_set_apic_base(CPUX86State *env, uint64_t val); -uint64_t cpu_get_apic_base(CPUX86State *env); -void cpu_set_apic_tpr(CPUX86State *env, uint8_t val); -#ifndef NO_CPU_IO_DEFS -uint8_t cpu_get_apic_tpr(CPUX86State *env); -#endif void cpu_smm_update(CPUX86State *env); /* will be suppressed */ Index: kvm/qemu/qemu-kvm.c =================================================================== --- kvm.orig/qemu/qemu-kvm.c +++ kvm/qemu/qemu-kvm.c @@ -7,6 +7,7 @@ #include "exec.h" #include "qemu-kvm.h" +#include "pic.h" #include #include @@ -215,9 +216,9 @@ static void load_regs(CPUState *env) sregs.cr3 = env->cr[3]; sregs.cr4 = env->cr[4]; - sregs.apic_base = cpu_get_apic_base(env); + sregs.apic_base = apic_get_base(env); sregs.efer = env->efer; - sregs.cr8 = cpu_get_apic_tpr(env); + sregs.cr8 = apic_get_tpr(env); kvm_set_sregs(kvm_context, 0, &sregs); @@ -298,7 +299,7 @@ static void save_regs(CPUState *env) env->cr[3] = sregs.cr3; env->cr[4] = sregs.cr4; - cpu_set_apic_base(env, sregs.apic_base); + apic_set_base(env, sregs.apic_base); env->efer = sregs.efer; //cpu_set_apic_tpr(env, sregs.cr8); @@ -403,7 +404,7 @@ static void post_kvm_run(void *opaque, s env->eflags = (kvm_run->if_flag) ? env->eflags | IF_MASK:env->eflags & ~IF_MASK; env->ready_for_interrupt_injection = kvm_run->ready_for_interrupt_injection; //cpu_set_apic_tpr(env, kvm_run->cr8); - cpu_set_apic_base(env, kvm_run->apic_base); + apic_set_base(env, kvm_run->apic_base); } static void pre_kvm_run(void *opaque, struct kvm_run *kvm_run) @@ -411,7 +412,7 @@ static void pre_kvm_run(void *opaque, st CPUState **envs = opaque, *env; env = envs[0]; - kvm_run->cr8 = cpu_get_apic_tpr(env); + kvm_run->cr8 = apic_get_tpr(env); } void kvm_load_registers(CPUState *env) Index: kvm/qemu/target-i386/helper.c =================================================================== --- kvm.orig/qemu/target-i386/helper.c +++ kvm/qemu/target-i386/helper.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "exec.h" +#include "pic.h" #ifdef USE_KVM extern int kvm_allowed; #endif @@ -2650,7 +2651,7 @@ void helper_movl_crN_T0(int reg) cpu_x86_update_cr4(env, T0); break; case 8: - cpu_set_apic_tpr(env, T0); + apic_set_tpr(env, T0); break; default: env->cr[reg] = T0; @@ -2708,7 +2709,7 @@ void helper_wrmsr(void) env->sysenter_eip = val; break; case MSR_IA32_APICBASE: - cpu_set_apic_base(env, val); + apic_set_base(env, val); break; case MSR_EFER: { @@ -2772,7 +2773,7 @@ void helper_rdmsr(void) val = env->sysenter_eip; break; case MSR_IA32_APICBASE: - val = cpu_get_apic_base(env); + val = apic_get_base(env); break; case MSR_EFER: val = env->efer; Index: kvm/qemu/target-i386/op.c =================================================================== --- kvm.orig/qemu/target-i386/op.c +++ kvm/qemu/target-i386/op.c @@ -20,6 +20,7 @@ #define ASM_SOFTMMU #include "exec.h" +#include "pic.h" /* n must be a constant to be efficient */ static inline target_long lshift(target_long x, int n) @@ -1246,7 +1247,7 @@ void OPPROTO op_movl_crN_T0(void) #if !defined(CONFIG_USER_ONLY) void OPPROTO op_movtl_T0_cr8(void) { - T0 = cpu_get_apic_tpr(env); + T0 = apic_get_tpr(env); } #endif Index: kvm/qemu/pic.h =================================================================== --- /dev/null +++ kvm/qemu/pic.h @@ -0,0 +1,52 @@ +/************************************************************************ + * pic.h: Provides an indirection layer for the (A)PIC which allows + * dynamic substituion of the interrupt handling code. This + * will allow us to selectively chose the KVM in-kernel apic + * emulation vs the QEMU user-space apic emulation. Support + * for both is key to allow "--no-kvm" type operation to continue + * working even after the in-kernel code is deployed. + * + * Written by: Gregory Haskins + * + ***********************************************************************/ + +#ifndef QEMU_PIC_H +#define QEMU_PIC_H + +typedef struct PIC_tag +{ + void (*set)(struct PIC_tag *this, int irq, int level); + int (*read)(struct PIC_tag *this); + uint32_t (*intack_read)(struct PIC_tag *this); + void (*update)(struct PIC_tag *this); + void (*info)(struct PIC_tag *this); + void (*stat)(struct PIC_tag *this); + + void *private; +}PIC; + +extern PIC *isa_pic; +#define pic_set_irq(irq, level) isa_pic->set(isa_pic, irq, level) +#define pic_set_irq_new(pic, irq, level) pic->set(pic, irq, level) +#define pic_read_irq(pic) pic->read(pic) +#define pic_intack_read(pic) pic->intack_read(pic) +#define pic_update_irq(pic) pic->update(pic) + +typedef struct APIC_tag +{ + int (*read_irq)(void *this); + void (*set_base)(void *this, uint64_t val); + uint64_t (*get_base)(void *this); + void (*set_tpr)(void *this, uint8_t val); + uint8_t (*get_tpr)(void *this); + + void *private; +}APIC; + +#define apic_read_irq(env) ((APIC*)(env->apic))->read_irq(env->apic) +#define apic_set_base(env, val) ((APIC*)(env->apic))->set_base(env->apic, val) +#define apic_get_base(env) ((APIC*)(env->apic))->get_base(env->apic) +#define apic_set_tpr(env, val) ((APIC*)(env->apic))->set_tpr(env->apic, val) +#define apic_get_tpr(env) ((APIC*)(env->apic))->get_tpr(env->apic) + +#endif /* QEMU_PIC_H */