Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---
qemu/hw/apic.c | 20 +++++++++++++++-----
qemu/hw/pc.c | 29 ++++++++++++++++-------------
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, 145 insertions(+), 32 deletions(-)
diff --git a/qemu/hw/apic.c b/qemu/hw/apic.c
index 5704224..901f3b6 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;
@@ -895,10 +897,17 @@ 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);
+ cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ } else {
+ apic_get_delivery_bitmask(deliver_bitmask, dest,
+ dest_mode);
+ apic_bus_deliver(deliver_bitmask, delivery_mode,
+ vector, polarity, trig_mode);
+ }
}
}
}
@@ -1052,7 +1061,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 +1070,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..df51539 100644
--- a/qemu/hw/pc.c
+++ b/qemu/hw/pc.c
@@ -91,16 +91,19 @@ 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;
+ 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;
}
- /* read the irq from the PIC */
- if (!apic_accept_pic_intr(env))
- return -1;
intno = pic_read_irq(isa_pic);
return intno;
@@ -483,9 +486,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 +674,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 d184cbd..1192fbb 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)
@@ -682,7 +710,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
[email protected]
https://lists.sourceforge.net/lists/listinfo/kvm-devel