QEMU PIC indirection patch for in-kernel APIC work

Gregory Haskins
2007-04-02T11:46:09Z

[-- Attachment #1: Type: text/plain, Size: 1381 bytes --]

Hi Dor,
Please find a patch attached for your review which adds support for dynamic substitution of the PIC/APIC code to QEMU. 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.

Note that this is only the part the allows indirection. The code that actually fills in the "slim apic" in QEMU, as well as the kernel side changes applied to git are not included here. Note also that this patch can stand alone. I have confirmed that I can boot a guest with no discernible difference in behavior/performance both before and after this patch. YMMV as my test cases are limited.

Note that this patch only touches the KVM specific portions of QEMU (namely, x86/i8259/apic support). If we decide that this should be pushed to QEMU upstream, there is still work to be done to convert the other PIC implementations (e.g. arm_pic, etc) to use the new interface.

I will continue to work on the kernel/slim-apic side while I await your feedback. (BTW: Thanks for pointing me towards your branch...it has been most helpful rather than starting from scratch. I already have most of the kernel-side code ported already in a separate queue which I will share once I get a baseline).

Thanks!

-Greg

[-- Attachment #2: qemu_pic_indirection.patch --]
[-- Type: text/plain, Size: 22102 bytes --]

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 <kvmctl.h>
#include <string.h>

@@ -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 <ghaskins-Et1tbQHTxzrQT0dZR+AlfA@public.gmane.org>
+ *
+ ***********************************************************************/
+
+#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 */

[-- Attachment #3: Type: text/plain, Size: 345 bytes --]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org