Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]> --- qemu/hw/apic.c | 35 ++++++++++++++++++++++++++--------- qemu/hw/pc.c | 34 ++++++++++++++++++++-------------- qemu/qemu-kvm.c | 49 +++++++++++++++++++++++++++++++++++++++---------- qemu/qemu-kvm.h | 2 ++ qemu/vl.h | 11 ++++++++++- user/kvmctl.c | 33 ++++++++++++++++++++++++++++++++- user/kvmctl.h | 31 ++++++++++++++++++++++++++++++- user/main.c | 2 +- 8 files changed, 160 insertions(+), 37 deletions(-)
diff --git a/qemu/hw/apic.c b/qemu/hw/apic.c index 5704224..dee547d 100644 --- a/qemu/hw/apic.c +++ b/qemu/hw/apic.c @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "vl.h" +#include "qemu-kvm.h" //#define DEBUG_APIC //#define DEBUG_IOAPIC @@ -87,6 +88,7 @@ typedef struct APICState { } APICState; struct IOAPICState { + CPUState *cpu_env; uint8_t id; uint8_t ioregsel; @@ -866,7 +868,7 @@ int apic_init(CPUState *env) return 0; } -static void ioapic_service(IOAPICState *s) +void ioapic_service(IOAPICState *s) { uint8_t i; uint8_t trig_mode; @@ -895,15 +897,29 @@ static void ioapic_service(IOAPICState *s) vector = pic_read_irq(isa_pic); else vector = entry & 0xff; - - apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - apic_bus_deliver(deliver_bitmask, delivery_mode, - vector, polarity, trig_mode); + + if (use_kernel_apic()) + ext_apic_bus_deliver(dest, trig_mode, dest_mode, + delivery_mode, vector); + else { + apic_get_delivery_bitmask(deliver_bitmask, dest, + dest_mode); + apic_bus_deliver(deliver_bitmask, delivery_mode, + vector, polarity, trig_mode); + } } } } } +static void __ioapic_service(IOAPICState *s) +{ + if (use_kernel_apic()) + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + else + ioapic_service(s); +} + void ioapic_set_irq(void *opaque, int vector, int level) { IOAPICState *s = opaque; @@ -916,7 +932,7 @@ void ioapic_set_irq(void *opaque, int vector, int level) /* level triggered */ if (level) { s->irr |= mask; - ioapic_service(s); + __ioapic_service(s); } else { s->irr &= ~mask; } @@ -924,7 +940,7 @@ void ioapic_set_irq(void *opaque, int vector, int level) /* edge triggered */ if (level) { s->irr |= mask; - ioapic_service(s); + __ioapic_service(s); } } } @@ -996,7 +1012,7 @@ static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va s->ioredtbl[index] &= ~0xffffffffULL; s->ioredtbl[index] |= val; } - ioapic_service(s); + __ioapic_service(s); } } } @@ -1052,7 +1068,7 @@ static CPUWriteMemoryFunc *ioapic_mem_write[3] = { ioapic_mem_writel, }; -IOAPICState *ioapic_init(void) +IOAPICState *ioapic_init(CPUState *env) { IOAPICState *s; int io_memory; @@ -1061,6 +1077,7 @@ IOAPICState *ioapic_init(void) if (!s) return NULL; ioapic_reset(s); + s->cpu_env = env; s->id = last_apic_id++; io_memory = cpu_register_io_memory(0, ioapic_mem_read, diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c index eda49cf..8de5911 100644 --- a/qemu/hw/pc.c +++ b/qemu/hw/pc.c @@ -46,6 +46,8 @@ static PITState *pit; static IOAPICState *ioapic; static PCIDevice *i440fx_state; +void ioapic_service(IOAPICState *s); + static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { } @@ -91,16 +93,20 @@ 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 */ - if (!apic_accept_pic_intr(env)) - return -1; + if (!use_kernel_apic()) { + 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 */ + if (!apic_accept_pic_intr(env)) + return -1; + } else + ioapic_service(ioapic); intno = pic_read_irq(isa_pic); return intno; @@ -483,9 +489,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, } register_savevm("cpu", i, 4, cpu_save, cpu_load, env); qemu_register_reset(main_cpu_reset, env); - if (pci_enabled) { - apic_init(env); - } + if (!use_kernel_apic() && pci_enabled) { + apic_init(env); + } } /* allocate RAM */ @@ -671,7 +677,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, register_ioport_write(0x92, 1, 1, ioport92_write, NULL); if (pci_enabled) { - ioapic = ioapic_init(); + ioapic = ioapic_init(env); } isa_pic = pic_init(pic_irq_request, first_cpu); pit = pit_init(0x40, 0); diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c index 106772b..53990d8 100644 --- a/qemu/qemu-kvm.c +++ b/qemu/qemu-kvm.c @@ -245,9 +245,16 @@ static void load_regs(CPUState *env) sregs.cr3 = env->cr[3]; sregs.cr4 = env->cr[4]; - sregs.apic_base = cpu_get_apic_base(env); + if (!kvm_apic.level) { + /* These two are no longer used once the in-kernel APIC is enabled */ + sregs.apic_base = 0; + sregs.cr8 = 0; + } else { + sregs.apic_base = cpu_get_apic_base(env); + sregs.cr8 = cpu_get_apic_tpr(env); + } + sregs.efer = env->efer; - sregs.cr8 = cpu_get_apic_tpr(env); kvm_set_sregs(kvm_context, 0, &sregs); @@ -339,10 +346,12 @@ static void save_regs(CPUState *env) env->cr[3] = sregs.cr3; env->cr[4] = sregs.cr4; - cpu_set_apic_base(env, sregs.apic_base); + if (!kvm_apic.level) { + cpu_set_apic_base(env, sregs.apic_base); + //cpu_set_apic_tpr(env, sregs.cr8); + } env->efer = sregs.efer; - //cpu_set_apic_tpr(env, sregs.cr8); #define HFLAG_COPY_MASK ~( \ HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \ @@ -428,9 +437,17 @@ static int try_push_interrupts(void *opaque) if (env->ready_for_interrupt_injection && (env->interrupt_request & CPU_INTERRUPT_HARD) && (env->eflags & IF_MASK)) { + int irq = cpu_get_pic_interrupt(env); + + if (irq != -1) { + if (kvm_apic.level) + kvm_inject_isa_irq(kvm_context, irq); + else + // for now using cpu 0 + kvm_inject_irq(kvm_context, 0, irq); + } + env->interrupt_request &= ~CPU_INTERRUPT_HARD; - // for now using cpu 0 - kvm_inject_irq(kvm_context, 0, cpu_get_pic_interrupt(env)); } return (env->interrupt_request & CPU_INTERRUPT_HARD) != 0; @@ -445,8 +462,11 @@ static void post_kvm_run(void *opaque, int vcpu) ? env->eflags | IF_MASK : env->eflags & ~IF_MASK; env->ready_for_interrupt_injection = kvm_is_ready_for_interrupt_injection(kvm_context, vcpu); - //cpu_set_apic_tpr(env, kvm_run->cr8); - cpu_set_apic_base(env, kvm_get_apic_base(kvm_context, vcpu)); + + if (!kvm_apic.level) { + //cpu_set_apic_tpr(env, kvm_run->cr8); + cpu_set_apic_base(env, kvm_get_apic_base(kvm_context, vcpu)); + } } static void pre_kvm_run(void *opaque, int vcpu) @@ -454,7 +474,15 @@ static void pre_kvm_run(void *opaque, int vcpu) CPUState **envs = opaque, *env; env = envs[0]; - kvm_set_cr8(kvm_context, vcpu, cpu_get_apic_tpr(env)); + if (!kvm_apic.level) + kvm_set_cr8(kvm_context, vcpu, cpu_get_apic_tpr(env)); +} + +int ext_apic_bus_deliver(int dest, int trig_mode, int dest_mode, + int delivery_mode, int vector) +{ + return kvm_apic_bus_deliver(kvm_context, dest, trig_mode, dest_mode, + delivery_mode, vector); } void kvm_load_registers(CPUState *env) @@ -679,7 +707,8 @@ int kvm_qemu_create_context(void) { int i; - if (kvm_create(kvm_context, phys_ram_size, (void**)&phys_ram_base) < 0) { + if (kvm_create(kvm_context, phys_ram_size, kvm_apic.level, + (void**)&phys_ram_base) < 0) { kvm_qemu_destroy(); return -1; } diff --git a/qemu/qemu-kvm.h b/qemu/qemu-kvm.h index c4cb34e..2dd5e00 100644 --- a/qemu/qemu-kvm.h +++ b/qemu/qemu-kvm.h @@ -8,6 +8,8 @@ int kvm_qemu_init(void); int kvm_qemu_create_context(void); void kvm_qemu_destroy(void); +int ext_apic_bus_deliver(int dest, int trig_mode, int dest_mode, + int delivery_mode, int vector); void kvm_load_registers(CPUState *env); void kvm_save_registers(CPUState *env); int kvm_cpu_exec(CPUState *env); diff --git a/qemu/vl.h b/qemu/vl.h index 4e93a81..514a86b 100644 --- a/qemu/vl.h +++ b/qemu/vl.h @@ -167,6 +167,15 @@ extern int semihosting_enabled; extern int autostart; extern int time_drift_fix; +static inline int use_kernel_apic() +{ +#ifdef USE_KVM + return kvm_allowed && kvm_qemu_get_apic_level(); +#else + return 0; +#endif +} + #define MAX_OPTION_ROMS 16 extern const char *option_rom[MAX_OPTION_ROMS]; extern int nb_option_roms; @@ -1060,7 +1069,7 @@ typedef struct IOAPICState IOAPICState; int apic_init(CPUState *env); int apic_get_interrupt(CPUState *env); int apic_accept_pic_intr(CPUState *env); -IOAPICState *ioapic_init(void); +IOAPICState *ioapic_init(CPUState *env); void ioapic_set_irq(void *opaque, int vector, int level); /* i8254.c */ diff --git a/user/kvmctl.c b/user/kvmctl.c index 82d1926..70f9626 100644 --- a/user/kvmctl.c +++ b/user/kvmctl.c @@ -202,7 +202,8 @@ void kvm_finalize(kvm_context_t kvm) free(kvm); } -int kvm_create(kvm_context_t kvm, unsigned long memory, void **vm_mem) +int kvm_create(kvm_context_t kvm, unsigned long memory, int apic_level, + void **vm_mem) { unsigned long dosmem = 0xa0000; unsigned long exmem = 0xc0000; @@ -259,6 +260,14 @@ int kvm_create(kvm_context_t kvm, unsigned long memory, void **vm_mem) MAP_PRIVATE|MAP_FIXED, zfd, 0); close(zfd); + if (apic_level) { + r = ioctl(fd, KVM_ENABLE_KERNEL_PIC, &apic_level); + if (r == -1) { + fprintf(stderr, "kvm_enable_kernel_pic: %m\n"); + return -1; + } + } + r = ioctl(fd, KVM_CREATE_VCPU, 0); if (r == -1) { fprintf(stderr, "kvm_create_vcpu: %m\n"); @@ -999,6 +1008,28 @@ int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq) return ioctl(kvm->vcpu_fd[vcpu], KVM_INTERRUPT, &intr); } +int kvm_inject_isa_irq(kvm_context_t kvm, unsigned irq) +{ + struct kvm_interrupt intr; + + intr.irq = irq; + return ioctl(kvm->vm_fd, KVM_ISA_INTERRUPT, &intr); +} + +int kvm_apic_bus_deliver(kvm_context_t kvm, int dest, int trig_mode, + int dest_mode, int delivery_mode, int vector) +{ + struct kvm_apic_msg msg; + + msg.dest = dest; + msg.trig_mode = trig_mode; + msg.dest_mode = dest_mode; + msg.delivery_mode = delivery_mode; + msg.vector = vector; + + return ioctl(kvm->vm_fd, KVM_APIC_MSG, &msg); +} + int kvm_guest_debug(kvm_context_t kvm, int vcpu, struct kvm_debug_guest *dbg) { return ioctl(kvm->vcpu_fd[vcpu], KVM_DEBUG_GUEST, dbg); diff --git a/user/kvmctl.h b/user/kvmctl.h index b14cb45..9aab269 100644 --- a/user/kvmctl.h +++ b/user/kvmctl.h @@ -100,12 +100,14 @@ void kvm_finalize(kvm_context_t kvm); * * \param kvm Pointer to the current kvm_context * \param phys_mem_bytes The amount of physical ram you want the VM to have + * \param apic_level The APIC emulation level (0=QEMU, 1=KVM) * \param phys_mem This pointer will be set to point to the memory that * kvm_create allocates for physical RAM * \return 0 on success */ int kvm_create(kvm_context_t kvm, unsigned long phys_mem_bytes, + int apic_level, void **phys_mem); /*! @@ -280,11 +282,38 @@ int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n); * This allows you to simulate an external vectored interrupt. * * \param kvm Pointer to the current kvm_context - * \param vcpu Which virtual CPU should get dumped + * \param vcpu Which virtual CPU should handle interrupt * \param irq Vector number * \return 0 on success */ int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq); + +/*! + * \brief Simulate an external vectored interrupt to the ISA bus + * + * This allows you to simulate an external vectored interrupt. + * + * \param kvm Pointer to the current kvm_context + * \param irq Vector number + * \return 0 on success + */ +int kvm_inject_isa_irq(kvm_context_t kvm, unsigned irq); + +/*! + * \brief Simulate an external vectored interrupt to the APIC bus + * + * This allows you to simulate a vectored interrupt via the LAPIC mechanism. + * + * \param kvm Pointer to the current kvm_context + * \param dest Encoded destination + * \param trig_mode 0=edge-trigger, 1=level-trigger + * \param dest_mode Destination mode encoding + * \param delivery_mode Delivery_mode encoding + * \param vector The vector number + * \return 0 on success + */ +int kvm_apic_bus_deliver(kvm_context_t kvm, int dest, int trig_mode, + int dest_mode, int delivery_mode, int vector); int kvm_guest_debug(kvm_context_t, int vcpu, struct kvm_debug_guest *dbg); /*! diff --git a/user/main.c b/user/main.c index c5da89c..88ae9f4 100644 --- a/user/main.c +++ b/user/main.c @@ -180,7 +180,7 @@ int main(int ac, char **av) fprintf(stderr, "kvm_init failed\n"); return 1; } - if (kvm_create(kvm, 128 * 1024 * 1024, &vm_mem) < 0) { + if (kvm_create(kvm, 128 * 1024 * 1024, 1, &vm_mem) < 0) { kvm_finalize(kvm); fprintf(stderr, "kvm_create failed\n"); return 1; ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel