WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH][8/10] Infrastructure for interrupt handling.

To: Ian Pratt <Ian.Pratt@xxxxxxxxxxxx>, Keir Fraser <Keir.Fraser@xxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH][8/10] Infrastructure for interrupt handling.
From: Arun Sharma <arun.sharma@xxxxxxxxx>
Date: Wed, 29 Jun 2005 22:52:55 -0700
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Thu, 30 Jun 2005 05:48:23 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.4.1i
Infrastructure for interrupt handling.

- support interruptibility
- handle interrupt window exiting control appropriately
- Add ioapic device models imported from Bochs under LGPL
- generalize the interrupt architecture to support both PIC/APIC

This patch is necessary to fix several bugs on 32 bit VMX and prepares the
ground for adding a local APIC device model in the hypervisor.

Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
Signed-off-by: Arun Sharma <arun.sharma@xxxxxxxxx>

diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/exec-all.h
--- a/tools/ioemu/exec-all.h    Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/exec-all.h    Thu Jun 30 05:24:52 2005
@@ -573,7 +573,7 @@
 }
 #endif
 
-//#define DEBUG_UNUSED_IOPORT
-//#define DEBUG_IOPORT
+#define DEBUG_UNUSED_IOPORT
+#define DEBUG_IOPORT
 #define TARGET_VMX
 
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/hw/i8259.c
--- a/tools/ioemu/hw/i8259.c    Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/hw/i8259.c    Thu Jun 30 05:24:52 2005
@@ -22,12 +22,16 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
+#include "xc.h"
+#include <io/ioreq.h>
 
 /* debug PIC */
 //#define DEBUG_PIC
 
 //#define DEBUG_IRQ_LATENCY
 #define DEBUG_IRQ_COUNT
+
+extern void pit_reset_vmx_vectors();
 
 typedef struct PicState {
     uint8_t last_irr; /* edge detection */
@@ -121,6 +125,26 @@
     }
 }
 
+/* pic[1] is connected to pin2 of pic[0] */
+#define CASCADE_IRQ 2
+
+static void shared_page_update()
+{
+    extern shared_iopage_t *shared_page;
+    uint8_t * pmask = (uint8_t *)&(shared_page->sp_global.pic_mask[0]);
+    int           index;
+
+    index = pics[0].irq_base/8;
+    pmask[index] = pics[0].imr;
+    index = pics[1].irq_base/8;
+
+    if ( pics[0].imr &  (1 << CASCADE_IRQ) ) {
+        pmask[index] = 0xff;
+    } else {
+        pmask[index] = pics[1].imr;
+    }
+}
+
 /* raise irq to CPU if necessary. must be called every time the active
    irq may change */
 static void pic_update_irq(void)
@@ -150,14 +174,18 @@
 #endif
         cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
     }
+    shared_page_update();
 }
 
 #ifdef DEBUG_IRQ_LATENCY
 int64_t irq_time[16];
 #endif
 
+extern void ioapic_legacy_irq(int irq, int level);
+
 void pic_set_irq(int irq, int level)
 {
+    ioapic_legacy_irq(irq, level);
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
     if (level != irq_level[irq]) {
 #if defined(DEBUG_PIC)
@@ -255,6 +283,7 @@
     tmp = s->elcr_mask;
     memset(s, 0, sizeof(PicState));
     s->elcr_mask = tmp;
+    shared_page_update();
 }
 
 static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/target-i386-dm/helper2.c
--- a/tools/ioemu/target-i386-dm/helper2.c      Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/target-i386-dm/helper2.c      Thu Jun 30 05:24:52 2005
@@ -320,7 +320,7 @@
 
        // Send a message on the event channel. Add the vector to the shared mem
        // page.
-       intr = &(shared_page->vcpu_iodata[0].vp_intr[0]);
+       intr = &(shared_page->sp_global.pic_intr[0]);
        atomic_set_bit(vector, intr);
         if (loglevel & CPU_LOG_INT)
                 fprintf(logfile, "injecting vector: %x\n", vector);
@@ -345,11 +345,11 @@
        FD_ZERO(&rfds);
 
        while (1) {
-            if (vm_running) {
-                if (shutdown_requested) {
-                    break;
+                if (vm_running) {
+                    if (shutdown_requested) {
+                        break;
+                    }
                 }
-            }
 
                /* Wait up to one seconds. */
                tv.tv_sec = 0;
@@ -370,14 +370,19 @@
 #endif
 
                main_loop_wait(0);
-
+#ifdef APIC_SUPPORT
+               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();
+#endif
                if (env->send_event) {
                        int ret;
                        ret = xc_evtchn_send(xc_handle, ioreq_port);
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/include/asm-x86/vmx.h
--- a/xen/include/asm-x86/vmx.h Thu Jun 30 04:32:55 2005
+++ b/xen/include/asm-x86/vmx.h Thu Jun 30 05:24:52 2005
@@ -339,14 +339,19 @@
     return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
 }
 
+static inline shared_iopage_t *get_sp(struct domain *d)
+{
+    return (shared_iopage_t *) d->arch.vmx_platform.shared_page_va;
+}
+
 static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu)
 {
-    return &((shared_iopage_t *) 
d->arch.vmx_platform.shared_page_va)->vcpu_iodata[cpu];
+    return &get_sp(d)->vcpu_iodata[cpu];
 }
 
 static inline int iopacket_port(struct domain *d)
 {
-    return ((shared_iopage_t *) 
d->arch.vmx_platform.shared_page_va)->sp_global.eport;
+    return get_sp(d)->sp_global.eport;
 }
 
 #endif /* __ASM_X86_VMX_H__ */
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/arch/x86/vmx_vmcs.c
--- a/xen/arch/x86/vmx_vmcs.c   Thu Jun 30 04:32:55 2005
+++ b/xen/arch/x86/vmx_vmcs.c   Thu Jun 30 05:24:52 2005
@@ -153,6 +153,8 @@
     p = map_domain_page(mpfn);
     d->domain->arch.vmx_platform.shared_page_va = (unsigned long)p;
 
+   VMX_DBG_LOG(DBG_LEVEL_1, "eport: %x\n", iopacket_port(d->domain));
+
    clear_bit(iopacket_port(d->domain), 
              &d->domain->shared_info->evtchn_mask[0]);
 
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/include/asm-x86/vmx_virpit.h
--- a/xen/include/asm-x86/vmx_virpit.h  Thu Jun 30 04:32:55 2005
+++ b/xen/include/asm-x86/vmx_virpit.h  Thu Jun 30 05:24:52 2005
@@ -20,7 +20,7 @@
     int vector;                                /* the pit irq vector */
     unsigned int period;               /* the frequency. e.g. 10ms*/
     unsigned int channel;              /* the pit channel, counter 0~2 */
-    unsigned long *intr_bitmap;
+    u64  *intr_bitmap;
     unsigned int pending_intr_nr;      /* the couner for pending timer 
interrupts */
     unsigned long long inject_point;   /* the time inject virt intr */
     struct ac_timer pit_timer;         /* periodic timer for mode 2*/
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/target-i386-dm/Makefile
--- a/tools/ioemu/target-i386-dm/Makefile       Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/target-i386-dm/Makefile       Thu Jun 30 05:24:52 2005
@@ -188,7 +188,7 @@
 
 #########################################################
 
-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 
-DAPIC_SUPPORT
 LIBS+=-lm -L../../libxc -lxc
 ifndef CONFIG_USER_ONLY
 LIBS+=-lz
@@ -246,6 +246,7 @@
 # must use static linking to avoid leaving stuff in virtual address space
 VL_OBJS=vl.o exec.o monitor.o osdep.o block.o readline.o pci.o console.o 
 VL_OBJS+=block-cow.o block-qcow.o block-vmdk.o block-cloop.o aes.o
+VL_OBJS+=ioapic.o
 #VL_OBJS+= block-cloop.o
 
 SOUND_HW = sb16.o
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/hw/pc.c
--- a/tools/ioemu/hw/pc.c       Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/hw/pc.c       Thu Jun 30 05:24:52 2005
@@ -543,6 +543,9 @@
             pci_ne2000_init(pci_bus, &nd_table[i]);
         }
         pci_piix3_ide_init(pci_bus, bs_table);
+#ifdef APIC_SUPPORT
+        IOAPICInit();
+#endif
     } else {
         nb_nics1 = nb_nics;
         if (nb_nics1 > NE2000_NB_MAX)
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/arch/x86/vmx_io.c
--- a/xen/arch/x86/vmx_io.c     Thu Jun 30 04:32:55 2005
+++ b/xen/arch/x86/vmx_io.c     Thu Jun 30 05:24:52 2005
@@ -22,6 +22,7 @@
 #include <xen/lib.h>
 #include <xen/errno.h>
 #include <xen/trace.h>
+#include <xen/event.h>
 
 #include <asm/current.h>
 #include <asm/cpufeature.h>
@@ -29,10 +30,12 @@
 #include <asm/msr.h>
 #include <asm/vmx.h>
 #include <asm/vmx_vmcs.h>
-#include <xen/event.h>
-#include <public/io/ioreq.h>
 #include <asm/vmx_platform.h>
 #include <asm/vmx_virpit.h>
+#include <asm/apic.h>
+
+#include <public/io/ioreq.h>
+#include <public/io/vmx_vlapic.h>
 
 #ifdef CONFIG_VMX
 #if defined (__i386__)
@@ -515,38 +518,100 @@
     return __fls(pintr[0]);
 }
 
+#define BSP_CPU(d)    (!(d->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 *d)
-{
-    vcpu_iodata_t *vio;
-
-    vio = get_vio(d->domain, d->vcpu_id);
-
-    if (vio == 0) {
-        VMX_DBG_LOG(DBG_LEVEL_1, 
-                    "bad shared page: %lx", (unsigned long) vio);
-        domain_crash_synchronous();
-    }
-        
-    return find_highest_irq((unsigned int *)&vio->vp_intr[0]);
-}
-
-static inline void clear_highest_bit(struct vcpu *d, int vector)
-{
-    vcpu_iodata_t *vio;
-
-    vio = get_vio(d->domain, d->vcpu_id);
-
-    if (vio == 0) {
-        VMX_DBG_LOG(DBG_LEVEL_1, 
-                    "bad shared page: %lx", (unsigned long) vio);
-        domain_crash_synchronous();
-    }
-        
-    clear_bit(vector, &vio->vp_intr[0]);
+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)
+{
+    struct vmx_virpit_t *vpit = &(v->domain->arch.vmx_platform.vmx_pit);
+    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)
+                vpit->inject_point = NOW();
+            break;
+
+        default:
+            printk("Not support interrupt type\n");
+            break;
+    }
+}
+
+static inline void
+enable_irq_window(unsigned long cpu_exec_control)
+{
+    if (!(cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) {
+        cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
+    }
+}
+
+static inline void
+disable_irq_window(unsigned long cpu_exec_control)
+{
+    if ( cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) {
+        cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+        __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
+    }
 }
 
 static inline int irq_masked(unsigned long eflags)
@@ -554,50 +619,68 @@
     return ((eflags & X86_EFLAGS_IF) == 0);
 }
 
-void vmx_intr_assist(struct vcpu *d) 
-{
-    int highest_vector = find_highest_pending_irq(d);
-    unsigned long intr_fields, eflags;
-    struct vmx_virpit_t *vpit = &(d->domain->arch.vmx_platform.vmx_pit);
-
-    if (highest_vector == -1)
+void vmx_intr_assist(struct vcpu *v) 
+{
+    int intr_type;
+    int highest_vector = find_highest_pending_irq(v, &intr_type);
+    unsigned long intr_fields, eflags, interruptibility, cpu_exec_control;
+
+    __vmread(CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control);
+
+    if (highest_vector == -1) {
+        disable_irq_window(cpu_exec_control);
         return;
-
-    __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
-    if (intr_fields & INTR_INFO_VALID_MASK) {
-        VMX_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
-                    intr_fields);
-        return;
-    }
-
-    __vmread(GUEST_RFLAGS, &eflags);
-    if (irq_masked(eflags)) {
-        VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx",
-                    highest_vector, eflags);
-        return;
-    }
-        
-    if (vpit->pending_intr_nr && highest_vector == vpit->vector)
-        vpit->pending_intr_nr--;
-    else
-        clear_highest_bit(d, highest_vector); 
-
-    /* close the window between guest PIT initialization and sti */
-    if (highest_vector == vpit->vector && !vpit->first_injected){
-        vpit->first_injected = 1;
-        vpit->pending_intr_nr = 0;
-    }
-
-    intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
-    __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
-
-    __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
-
-    TRACE_3D(TRC_VMX_INT, d->domain->domain_id, highest_vector, 0);
-    if (highest_vector == vpit->vector)
-        vpit->inject_point = NOW();
-
-    return;
+    }
+
+     __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
+
+     if (intr_fields & INTR_INFO_VALID_MASK) {
+         VMX_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
+           intr_fields);
+         return;
+     }
+
+     __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
+
+     if (interruptibility) {
+         enable_irq_window(cpu_exec_control);
+         VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, interruptibility: 
%lx",
+                     highest_vector, interruptibility);
+         return;
+     }
+
+     __vmread(GUEST_RFLAGS, &eflags);
+
+     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;
+             }
+
+             intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR 
+                            | highest_vector);
+             __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
+             __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+
+             TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
+             break;
+         case VLAPIC_DELIV_MODE_FIXED:
+         case VLAPIC_DELIV_MODE_LPRI:
+         case VLAPIC_DELIV_MODE_SMI:
+         case VLAPIC_DELIV_MODE_NMI:
+         case VLAPIC_DELIV_MODE_INIT:
+         case VLAPIC_DELIV_MODE_STARTUP:
+         default:
+             printk("Unsupported interrupt type\n");
+             BUG();
+             break;
+     }
+
+     interrupt_post_injection(v, highest_vector, intr_type);
+     return;
 }
 
 void vmx_do_resume(struct vcpu *d) 
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/arch/x86/vmx_intercept.c
--- a/xen/arch/x86/vmx_intercept.c      Thu Jun 30 04:32:55 2005
+++ b/xen/arch/x86/vmx_intercept.c      Thu Jun 30 05:24:52 2005
@@ -213,7 +213,8 @@
 {
     vcpu_iodata_t * vio = get_vio(d->domain, d->vcpu_id);
     ioreq_t *p = &vio->vp_ioreq;
-    unsigned long *intr = &(vio->vp_intr[0]);
+    shared_iopage_t *sp = get_sp(d->domain);
+    u64 *intr = &(sp->sp_global.pic_intr[0]);
     struct vmx_virpit_t *vpit = &(d->domain->arch.vmx_platform.vmx_pit);
     int rw_mode;
 
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/hw/pci.c
--- a/tools/ioemu/hw/pci.c      Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/hw/pci.c      Thu Jun 30 05:24:52 2005
@@ -53,6 +53,7 @@
 static int pci_irq_index;
 static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
 static PCIBus *first_bus;
+extern FILE *logfile;
 
 static PCIBus *pci_register_bus(void)
 {
@@ -569,13 +570,26 @@
     pci_conf[0xae] = 0x00;
 }
 
+#define PIIX_CONFIG_XBCS 0x4f
+void piix3_write_config(PCIDevice *d,
+  uint32_t address, uint32_t val, int len)
+{
+    if ((PIIX3State *)d != piix3_state){
+        fprintf(logfile, "piix3_write_config: error PCIDevice\n");
+        return;
+    }
+
+    pci_default_write_config(d, address, val, len);
+}
+
+
 void piix3_init(PCIBus *bus)
 {
     PIIX3State *d;
     uint8_t *pci_conf;
 
     d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State),
-                                          -1, NULL, NULL);
+                                          -1, NULL, piix3_write_config);
     register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
 
     piix3_state = d;
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/include/public/io/ioreq.h
--- a/xen/include/public/io/ioreq.h     Thu Jun 30 04:32:55 2005
+++ b/xen/include/public/io/ioreq.h     Thu Jun 30 05:24:52 2005
@@ -49,14 +49,11 @@
 
 #define MAX_VECTOR    256
 #define BITS_PER_BYTE   8
-#define INTR_LEN        (MAX_VECTOR/(BITS_PER_BYTE * sizeof(unsigned long)))
+#define INTR_LEN        (MAX_VECTOR/(BITS_PER_BYTE * sizeof(u64)))
 
-/* We only track the master PIC state here */
 typedef struct {
-    uint16_t irr; /* interrupt request register */
-    uint16_t imr; /* interrupt mask register */
-    uint16_t isr; /* interrupt service register */
-
+    u64   pic_intr[INTR_LEN];
+    u64   pic_mask[INTR_LEN];
     int     eport; /* Event channel port */
 } global_iodata_t;
 
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/hw/ioapic.c
--- /dev/null   Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/hw/ioapic.c   Thu Jun 30 05:24:52 2005
@@ -0,0 +1,704 @@
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+
+#include "vl.h"
+#include "ioapic.h"
+
+#ifdef __OS
+#undef __OS
+#endif
+#ifdef __i386__
+#define __OS   "l"
+#else
+#define __OS "q"
+#endif
+#define ADDR (*(volatile long *) addr)
+
+#ifdef IOAPIC_DEBUG
+#define IOAPIC_LOG(a...) fprintf(logfile, ##a)
+#else
+#define IOAPIC_LOG(a...)
+#endif
+
+static IOAPICState *ioapic;
+
+#define IOAPIC_ERR(a...) fprintf(logfile, ##a)
+static __inline__ int test_and_set_bit(long nr, volatile void * addr)
+{
+       long oldbit;
+
+       __asm__ __volatile__( 
+               "bts"__OS" %2,%1\n\tsbb"__OS" %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"Ir" (nr) : "memory");
+       return oldbit;
+}
+
+static __inline__ int test_and_clear_bit(long nr, volatile void * addr)
+{
+       long oldbit;
+
+       __asm__ __volatile__( LOCK_PREFIX
+               "btr"__OS" %2,%1\n\tsbb"__OS" %0,%0"
+               :"=r" (oldbit),"=m" (ADDR)
+               :"dIr" (nr) : "memory");
+       return oldbit;
+}
+
+static __inline__ void clear_bit(long nr, volatile void * addr)
+{
+       __asm__ __volatile__( 
+               "btr"__OS" %1,%0"
+               :"=m" (ADDR)
+               :"Ir" (nr));
+}
+
+static inline
+void get_shareinfo_apic_msg(vlapic_info *share_info){
+    while(test_and_set_bit(VL_STATE_MSG_LOCK, &share_info->vl_state)){};
+}
+
+static inline
+void put_shareinfo_apic_msg(vlapic_info *share_info){
+    clear_bit(VL_STATE_MSG_LOCK, &share_info->vl_state);
+}
+static inline
+void get_shareinfo_eoi(vlapic_info *share_info){
+    while(test_and_set_bit(VL_STATE_EOI_LOCK, &share_info->vl_state)){};
+}
+
+static inline
+void put_shareinfo_eoi(vlapic_info *share_info){
+    clear_bit(VL_STATE_EOI_LOCK, &share_info->vl_state);
+}
+
+
+static inline
+void get_shareinfo_ext(vlapic_info *share_info){
+    while(test_and_set_bit(VL_STATE_EXT_LOCK, &share_info->vl_state));
+}
+
+static inline
+void put_shareinfo_ext(vlapic_info *share_info){
+    clear_bit(VL_STATE_EXT_LOCK, &share_info->vl_state);
+}
+
+
+static __inline__ int test_bit(int nr, uint32_t value){
+    return value & (1 << nr);
+}
+
+static void ioapic_enable(IOAPICState *s, uint8_t enable)
+{
+    if (!enable ^ IOAPICEnabled(s)) return;
+    if(enable)
+        s->flags |= IOAPIC_ENABLE_FLAG;
+    else
+        s->flags &= ~IOAPIC_ENABLE_FLAG;
+}
+
+#ifdef IOAPIC_DEBUG
+static void
+ioapic_dump_redir(IOAPICState *s, uint8_t entry)
+{
+    if (!s)
+        return;
+
+    RedirStatus redir = s->redirtbl[entry];
+
+    fprintf(logfile, "entry %x: "
+      "vector %x deliver_mod %x destmode %x delivestatus %x "
+      "polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n",
+      entry,
+      redir.RedirForm.vector, redir.RedirForm.deliver_mode,
+      redir.RedirForm.destmode, redir.RedirForm.delivestatus,
+      redir.RedirForm.polarity, redir.RedirForm.remoteirr,
+      redir.RedirForm.trigmod, redir.RedirForm.mask,
+      redir.RedirForm.dest_id);
+}
+
+static void
+ioapic_dump_shareinfo(IOAPICState *s , int number)
+{
+    if (!s || !s->lapic_info[number])
+        return;
+    vlapic_info *m = s->lapic_info[number];
+    IOAPIC_LOG("lapic_info %x : "
+      "vl_lapic_id %x vl_logical_dest %x vl_dest_format %x vl_arb_id %x\n",
+      number, m->vl_lapic_id, m->vl_logical_dest, m->vl_dest_format, 
m->vl_arb_id );
+}
+#endif
+
+static void
+ioapic_save(QEMUFile* f,void* opaque)
+{
+    IOAPIC_ERR("no implementation for ioapic_save\n");
+}
+
+static
+int ioapic_load(QEMUFile* f,void* opaque,int version_id)
+{
+    IOAPIC_ERR("no implementation for ioapic_load\n");
+    return 0;
+}
+
+uint32_t
+ioapic_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    IOAPIC_ERR("ioapic_mem_readb\n");
+    return 0;
+}
+
+uint32_t
+ioapic_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    IOAPIC_ERR("ioapic_mem_readw\n");
+    return 0;
+}
+
+static
+void ioapic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IOAPIC_ERR("ioapic_mem_writeb\n");
+}
+
+static
+void ioapic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IOAPIC_ERR("ioapic_mem_writew\n");
+}
+
+static
+uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    unsigned short ioregsel;
+    IOAPICState *s = opaque;
+    uint32_t    result = 0;
+    uint32_t    redir_index = 0;
+    uint64_t    redir_content = 0;
+
+    IOAPIC_LOG("apic_mem_readl addr %x\n", addr);
+    if (!s){
+        IOAPIC_ERR("null pointer for apic_mem_readl\n");
+        return result;
+    }
+
+    addr &= 0xff;
+    if(addr == 0x00){
+        result = s->ioregsel;
+        return result;
+    }else if (addr != 0x10){
+        IOAPIC_ERR("apic_mem_readl address error\n");
+        return result;
+    }
+
+    ioregsel = s->ioregsel;
+
+    switch (ioregsel){
+        case IOAPIC_REG_APIC_ID:
+            result = ((s->id & 0xf) << 24);
+            break;
+        case IOAPIC_REG_VERSION:
+            result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16)  
+                     | (IOAPIC_VERSION_ID & 0x0f));
+            break;
+        case IOAPIC_REG_ARB_ID:
+            //FIXME
+            result = ((s->id & 0xf) << 24);
+            break;
+        default:
+            redir_index = (ioregsel - 0x10) >> 1;
+            if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){
+               redir_content = s->redirtbl[redir_index].value;
+               result = (ioregsel & 0x1)?
+                        (redir_content >> 32) & 0xffffffff :
+                        redir_content & 0xffffffff;
+            }else{
+                IOAPIC_ERR(
+                  "upic_mem_readl:undefined ioregsel %x\n",
+                  ioregsel);
+            }
+    }
+    return result;
+}
+
+static
+void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    IOAPICState *s = opaque;
+    uint32_t redir_index = 0;
+    uint64_t redir_content;
+
+    IOAPIC_LOG("apic_mem_writel addr %x val %x\n", addr, val);
+
+    if (!s){
+        IOAPIC_ERR("apic_mem_writel: null opaque\n");
+        return;
+    }
+
+    addr &= 0xff;
+    if (addr == 0x00){
+        s->ioregsel = val;
+        return;
+    }else if (addr != 0x10){
+        IOAPIC_ERR("apic_mem_writel: unsupported address\n");
+    }
+
+    switch (s->ioregsel){
+        case IOAPIC_REG_APIC_ID:
+            s->id = (val >> 24) & 0xf;
+            break;
+        case IOAPIC_REG_VERSION:
+            IOAPIC_ERR("apic_mem_writel: version register read only\n");
+            break;
+        case IOAPIC_REG_ARB_ID:
+            s->arb_id = val;
+            break;
+        default:
+            redir_index = (s->ioregsel - 0x10) >> 1;
+//            IOAPIC_LOG("apic_mem_write: change redir :index %x before %lx, 
val %x\n", redir_index, s->redirtbl[redir_index].value, val);
+            if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS){
+                redir_content = s->redirtbl[redir_index].value;
+                if (s->ioregsel & 0x1)
+                   redir_content = (((uint64_t)val & 0xffffffff) << 32) | 
(redir_content & 0xffffffff);
+                else
+                    redir_content = ((redir_content >> 32) << 32) | (val & 
0xffffffff);
+                s->redirtbl[redir_index].value = redir_content;
+            }else {
+                IOAPIC_ERR("apic_mem_writel: error register\n");
+            }
+            //IOAPIC_LOG("after value is %lx\n",  
s->redirtbl[redir_index].value);
+    }
+}
+
+static CPUReadMemoryFunc *ioapic_mem_read[3] = {
+    ioapic_mem_readb,
+    ioapic_mem_readw,
+    ioapic_mem_readl,
+};
+
+static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
+    ioapic_mem_writeb,
+    ioapic_mem_writew,
+    ioapic_mem_writel,
+};
+
+void
+IOAPICReset(IOAPICState *s)
+{
+    int i;
+    if (!s)
+        return ;
+
+    memset(s, 0, sizeof(IOAPICState));
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++)
+        s->redirtbl[i].RedirForm.mask = 0x1;
+//    IOAPIC_LOG("after Reset %lx\n",  s->redirtbl[0].value);
+}
+
+void
+ioapic_update_config(IOAPICState *s, unsigned long address, uint8_t enable)
+{
+    int ioapic_mem;
+    if (!s)
+       return;
+
+    ioapic_enable(s, enable);
+
+    if (address != s->base_address){
+        ioapic_mem = cpu_register_io_memory(0, ioapic_mem_read, 
ioapic_mem_write, s);
+        cpu_register_physical_memory(address, IOAPIC_MEM_LENGTH, ioapic_mem);
+        s->base_address = ioapic_mem;
+    }
+}
+
+#define direct_intr(mode)   \
+  (mode == VLAPIC_DELIV_MODE_SMI || \
+   mode == VLAPIC_DELIV_MODE_NMI || \
+   mode == VLAPIC_DELIV_MODE_INIT ||\
+   mode == VLAPIC_DELIV_MODE_STARTUP)
+
+int
+ioapic_inj_irq(IOAPICState *s, uint8_t dest, uint8_t vector, uint8_t 
trig_mode, uint8_t delivery_mode)
+{
+    int msg_count;
+    if (!s || !s->lapic_info[dest]){
+        IOAPIC_ERR("ioapic_inj_irq NULL parameter\n");
+        return 0;
+    }
+    IOAPIC_LOG("ioapic_inj_irq %d , trig %d delive mode %d\n",
+      vector, trig_mode, delivery_mode);
+    switch(delivery_mode){
+        case VLAPIC_DELIV_MODE_FIXED:
+        case VLAPIC_DELIV_MODE_LPRI:
+            get_shareinfo_apic_msg(s->lapic_info[dest]);
+            msg_count = s->lapic_info[dest]->apic_msg_count;
+            s->lapic_info[dest]->vl_apic_msg[msg_count].deliv_mode = 
delivery_mode;
+            s->lapic_info[dest]->vl_apic_msg[msg_count].level = trig_mode;
+            s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector;
+            s->lapic_info[dest]->vl_apic_msg[msg_count].vector = vector;
+            s->lapic_info[dest]->apic_msg_count ++;
+            put_shareinfo_apic_msg(s->lapic_info[dest]);
+            break;
+        case VLAPIC_DELIV_MODE_EXT:
+/*            get_shareinfo_ext(s->lapic_info[dest]);
+            test_and_set_bit(vector, &s->lapic_info[dest]->vl_ext_intr[0]);
+            put_shareinfo_ext(s->lapic_info[dest]);*/
+            IOAPIC_ERR("<ioapic_inj_irq> Ext interrupt\n");
+            return 0;
+        default:
+            IOAPIC_ERR("<ioapic_inj_irq> error delivery mode\n");
+            break;
+    }
+    return 1;
+}
+
+int
+ioapic_match_logical_addr(IOAPICState *s, int number, uint8_t address)
+{
+    if(!s || !s->lapic_info[number]){
+        IOAPIC_ERR("ioapic_match_logical_addr NULL parameter: "
+          "number: %i s %p address %x\n",
+          number, s, address);
+        return 0;
+    }
+    IOAPIC_LOG("ioapic_match_logical_addr number %i address %x\n",
+      number, address);
+
+    if (((s->lapic_info[number]->vl_dest_format >> 28 ) & 0xf) != 0xf) {
+        IOAPIC_ERR("ioapic_match_logical_addr: cluster model not implemented 
still%x"
+          ,s->lapic_info[number]->vl_dest_format);
+#ifdef IOAPIC_DEBUG
+        ioapic_dump_shareinfo(s, number);
+#endif
+        return 0;
+    }
+    return ((address & ((s->lapic_info[number]->vl_logical_dest >> 24) & 
0xff)) != 0);
+}
+
+int
+ioapic_get_apr_lowpri(IOAPICState *s, int number)
+{
+    if(!s || !s->lapic_info[number]){
+        IOAPIC_ERR("ioapic_get_apr_lowpri NULL parameter\n");
+        return 0;
+    }
+    return s->lapic_info[number]->vl_arb_id;
+}
+
+uint32_t
+ioapic_get_delivery_bitmask(IOAPICState *s,
+uint8_t dest, uint8_t dest_mode, uint8_t vector, uint8_t delivery_mode)
+{
+    uint32_t mask = 0;
+    int low_priority = 256, selected = -1, i;
+    fprintf(logfile, "<ioapic_get_delivery_bitmask>: dest %d dest_mode %d"
+      "vector %d del_mode %d, lapic_count %d\n",
+      dest, dest_mode, vector, delivery_mode, s->lapic_count);
+    if (!s) return mask;
+    if (dest_mode == 0) { //Physical mode
+        if ((dest < s->lapic_count) && s->lapic_info[dest])
+            mask = 1 << dest;
+    }
+    else {
+        /* logical destination. call match_logical_addr for each APIC. */
+        if (dest == 0) return 0;
+        for (i=0; i< s->lapic_count; i++) {
+            //FIXME focus one, since no such issue on IPF, shoudl we add it?
+            if ( s->lapic_info[i] && ioapic_match_logical_addr(s, i, dest)){
+                if (delivery_mode != APIC_DM_LOWPRI)
+                    mask |= (1<<i);
+                else {
+                    if (low_priority > ioapic_get_apr_lowpri(s, i)){
+                        low_priority = ioapic_get_apr_lowpri(s, i);
+                        selected = i;
+                    }
+                    fprintf(logfile, "%d low_priority %d apr %d select %d\n",
+                      i, low_priority, ioapic_get_apr_lowpri(s, i), selected);
+                }
+            }
+        }
+        if (delivery_mode == APIC_DM_LOWPRI && (selected != -1)) 
+            mask |= (1<< selected);
+    }
+  return mask;
+}
+
+void
+ioapic_deliver(IOAPICState *s, int irqno){
+    uint8_t dest = s->redirtbl[irqno].RedirForm.dest_id;
+    uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode;
+    uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode;
+    uint8_t vector = s->redirtbl[irqno].RedirForm.vector;
+    uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod;
+    uint8_t bit;
+    uint32_t deliver_bitmask; 
+
+    IOAPIC_LOG("IOAPIC deliver: "
+      "dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n",
+      dest, dest_mode, delivery_mode, vector, trig_mode);
+
+    deliver_bitmask =
+      ioapic_get_delivery_bitmask(s, dest, dest_mode, vector, delivery_mode);
+
+      IOAPIC_LOG("ioapic_get_delivery_bitmask return %x\n", deliver_bitmask);
+    if (!deliver_bitmask){
+        IOAPIC_ERR("Ioapic deliver, no target on destination\n");
+        return ;
+    }
+
+    switch (delivery_mode){
+        case VLAPIC_DELIV_MODE_FIXED:
+        case VLAPIC_DELIV_MODE_LPRI:
+        case VLAPIC_DELIV_MODE_EXT:
+            break;
+        case VLAPIC_DELIV_MODE_SMI:
+        case VLAPIC_DELIV_MODE_NMI:
+        case VLAPIC_DELIV_MODE_INIT:
+        case VLAPIC_DELIV_MODE_STARTUP:
+        default:
+            IOAPIC_ERR("Not support delivey mode %d\n", delivery_mode);
+            return ;
+    }
+
+    for (bit = 0; bit < s->lapic_count; bit++){
+        if (deliver_bitmask & (1 << bit)){
+            if (s->lapic_info[bit]){
+                ioapic_inj_irq(s, bit, vector, trig_mode, delivery_mode);
+            }
+        }
+    }
+}
+
+static inline int __fls(u32 word)
+{
+    int bit;
+    __asm__("bsrl %1,%0"
+      :"=r" (bit)
+      :"rm" (word));
+    return word ? bit : -1;
+}
+
+#if 0
+static __inline__ int find_highest_bit(unsigned long *data, int length){
+    while(length && !data[--length]);
+    return __fls(data[length]) +  32 * length;
+}
+#endif
+int
+ioapic_get_highest_irq(IOAPICState *s){
+    uint32_t irqs;
+    if (!s)
+        return -1;
+    irqs = s->irr & ~s->isr;
+    return __fls(irqs);
+}
+
+
+void
+service_ioapic(IOAPICState *s){
+    int irqno;
+
+    while((irqno = ioapic_get_highest_irq(s)) != -1){
+        IOAPIC_LOG("service_ioapic: highest irqno %x\n", irqno);
+
+        if (!s->redirtbl[irqno].RedirForm.mask)
+            ioapic_deliver(s, irqno);
+
+        if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){
+            s->isr |= (1 << irqno);
+        }
+ //       clear_bit(irqno, &s->irr);
+        s->irr &= ~(1 << irqno);
+    }
+}
+
+void
+ioapic_update_irq(IOAPICState *s)
+{
+    s->INTR = 1;
+}
+
+void
+ioapic_set_irq(IOAPICState *s, int irq, int level)
+{
+    IOAPIC_LOG("ioapic_set_irq %x %x\n", irq, level);
+
+    /* Timer interrupt implemented on HV side */
+    if(irq == 0x0) return;
+    if (!s){
+        fprintf(logfile, "ioapic_set_irq null parameter\n");
+        return;
+    }
+    if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask)
+        return;
+#ifdef IOAPIC_DEBUG
+    ioapic_dump_redir(s, irq);
+#endif
+    if (irq >= 0 && irq < IOAPIC_NUM_PINS){
+        uint32_t bit = 1 << irq;
+        if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER){
+            if(level)
+                s->irr |= bit;
+            else
+                s->irr &= ~bit;
+        }else{
+            if(level)
+                /* XXX No irr clear for edge interrupt */
+                s->irr |= bit;
+        }
+    }
+
+    ioapic_update_irq(s);
+}
+
+void
+ioapic_legacy_irq(int irq, int level)
+{
+    ioapic_set_irq(ioapic, irq, level);
+}
+
+static inline int find_highest_bit(u32 *data, int length){
+        while(length && !data[--length]);
+            return __fls(data[length]) +  32 * length;
+}
+
+int
+get_redir_num(IOAPICState *s, int vector){
+    int i = 0;
+    if(!s){
+        IOAPIC_ERR("Null parameter for get_redir_num\n");
+        return -1;
+    }
+    for(; i < IOAPIC_NUM_PINS-1; i++){
+        if (s->redirtbl[i].RedirForm.vector == vector)
+            return i;
+    }
+    return -1;
+}
+
+void
+ioapic_update_EOI()
+{
+    int i = 0;
+    uint32_t isr_info ;
+    uint32_t vector;
+    IOAPICState *s = ioapic;
+
+    isr_info = s->isr;
+
+    for (i = 0; i < s->lapic_count; i++){
+        if (!s->lapic_info[i] ||
+          !test_bit(VL_STATE_EOI, s->lapic_info[i]->vl_state))
+            continue;
+        get_shareinfo_eoi(s->lapic_info[i]);
+        while((vector = find_highest_bit((unsigned int 
*)&s->lapic_info[i]->vl_eoi[0],VLAPIC_INT_COUNT_32)) != -1){
+            int redir_num;
+            if ((redir_num = get_redir_num(s, vector)) == -1){
+                IOAPIC_ERR("Can't find redir item for %d EOI \n", vector);
+                continue;
+            }
+            if (!test_and_clear_bit(redir_num, &s->isr)){
+                IOAPIC_ERR("redir %d not set for %d  EOI\n", redir_num, 
vector);
+                continue;
+            }
+            clear_bit(vector, &s->lapic_info[i]->vl_eoi[0]); 
+        }
+        clear_bit(VL_STATE_EOI, &s->lapic_info[i]->vl_state);
+        put_shareinfo_eoi(s->lapic_info[i]);
+    }
+}
+
+
+void
+ioapic_init_apic_info(IOAPICState *s)
+{
+#ifdef IOAPIC_DEBUG
+    fprintf(logfile, "ioapic_init_apic_info\n");
+    if (!s)
+        return;
+#endif
+
+#if 0
+    if (!vio || !(vio->vl_number)){
+        fprintf(logfile, "null vio or o vl number\n");
+        return;
+    }
+
+    for (i = 0; i < MAX_LAPIC_NUM; i++) s->lapic_info[i] = NULL;
+
+    s->lapic_count = vio->vl_number;
+    for (i = 0; i < vio->vl_number; i++)
+        s->lapic_info[i] = vio->vl_info + i;
+#endif
+
+}
+
+void
+ioapic_intack(IOAPICState *s)
+{
+#ifdef IOAPIC_DEBUG
+    if (!s){
+        fprintf(logfile, "ioapic_intack null parameter\n");
+        return;
+    }
+#endif
+    if (!s) s->INTR = 0;
+}
+
+int
+ioapic_has_intr()
+{
+    return ioapic->INTR;
+}
+
+void
+do_ioapic()
+{
+    service_ioapic(ioapic);
+    ioapic_intack(ioapic);
+}
+
+IOAPICState *
+IOAPICInit( )
+{
+    IOAPICState *s;
+
+    s = qemu_mallocz(sizeof(IOAPICState));
+    if (!s){
+        fprintf(logfile, "IOAPICInit: malloc failed\n");
+        return NULL;
+    }
+
+    IOAPICReset(s);
+    ioapic_init_apic_info(s);
+    register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
+    /* Remove after GFW ready */
+    ioapic_update_config(s, 0xfec00000, 1);
+
+    ioapic = s;
+    return s;
+}
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 tools/ioemu/hw/ioapic.h
--- /dev/null   Thu Jun 30 04:32:55 2005
+++ b/tools/ioemu/hw/ioapic.h   Thu Jun 30 05:24:52 2005
@@ -0,0 +1,128 @@
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+
+#ifndef __IOAPIC_H
+#define __IOAPIC_H
+
+#include "xc.h"
+#include <io/ioreq.h>
+#include <io/vmx_vlapic.h>
+
+#define IOAPIC_NUM_PINS 24
+#define IOAPIC_VERSION_ID 0x11
+#define IOAPIC_LEVEL_TRIGGER 1
+#define APIC_DM_FIXED  0
+#define APIC_DM_LOWPRI 1
+
+
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+#ifdef __I386__
+#define __OS "q" 
+#define __OP "r" 
+#else
+#define __OS "l"  /* Operation Suffix */
+#define __OP "e"  /* Operand Prefix */
+#endif
+
+#define ADDR (*(volatile long *) addr)
+#if 0
+#endif
+extern void *shared_page;
+extern FILE *logfile;
+#ifdef __BIGENDIAN__
+typedef union RedirStatus
+{
+    uint64_t value;
+    struct {
+        uint8_t dest_id;
+        uint8_t reserved[4];
+        uint8_t reserve:7;
+        uint8_t mask:1;         /* interrupt mask*/
+        uint8_t trigmod:1;
+        uint8_t remoteirr:1;
+        uint8_t polarity:1;
+        uint8_t delivestatus:1;
+        uint8_t destmode:1;
+        uint8_t deliver_mode:3;
+        uint8_t vector;
+    }RedirForm;
+}RedirStatus;
+#else
+typedef union RedirStatus
+{
+    uint64_t value;
+    struct {
+        uint8_t vector;
+        uint8_t deliver_mode:3;
+        uint8_t destmode:1;
+        uint8_t delivestatus:1;
+        uint8_t polarity:1;
+        uint8_t remoteirr:1;
+        uint8_t trigmod:1;
+        uint8_t mask:1;         /* interrupt mask*/
+        uint8_t reserve:7;
+        uint8_t reserved[4];
+        uint8_t dest_id;
+    }RedirForm;
+}RedirStatus;
+#endif
+/*
+ * IOAPICState stands for a instance of a IOAPIC
+ */
+
+/* FIXME tmp before working with Local APIC */
+#define IOAPIC_MEM_LENGTH 0x100
+#define IOAPIC_ENABLE_MASK 0x0
+#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK)
+#define MAX_LAPIC_NUM 32
+
+struct IOAPICState{
+    uint32_t INTR;
+    uint32_t id;
+    uint32_t arb_id;
+    uint32_t  flags;
+    unsigned long base_address;
+    uint32_t irr;
+    uint32_t isr;           /* This is used for level trigger */
+    uint8_t  vector_irr[256];
+    RedirStatus redirtbl[IOAPIC_NUM_PINS];
+    uint32_t ioregsel;
+    uint32_t lapic_count;
+    vlapic_info *lapic_info[MAX_LAPIC_NUM];
+};
+#define IOAPIC_REG_APIC_ID 0x0
+#define IOAPIC_REG_VERSION 0x1
+#define IOAPIC_REG_ARB_ID  0x2
+#define IOAPICEnabled(s) (s->flags & IOAPIC_ENABLE_FLAG)
+
+typedef struct IOAPICState IOAPICState;
+
+#endif
diff -r 96a4c0de6e53 -r 2d6fd3bba3c2 xen/include/public/io/vmx_vlapic.h
--- /dev/null   Thu Jun 30 04:32:55 2005
+++ b/xen/include/public/io/vmx_vlapic.h        Thu Jun 30 05:24:52 2005
@@ -0,0 +1,57 @@
+#ifndef _VMX_VLAPIC_H
+#define _VMX_VLAPIC_H
+
+/*
+   We extended one bit for PIC type
+ */
+#define VLAPIC_DELIV_MODE_FIXED          0x0
+#define VLAPIC_DELIV_MODE_LPRI           0x1
+#define VLAPIC_DELIV_MODE_SMI            0x2
+#define VLAPIC_DELIV_MODE_NMI            0x4
+#define VLAPIC_DELIV_MODE_INIT           0x5
+#define VLAPIC_DELIV_MODE_STARTUP        0x6
+#define VLAPIC_DELIV_MODE_EXT            0x7
+#define VLAPIC_DELIV_MODE_MASK            0x8
+
+#define VLAPIC_MSG_LEVEL                4
+
+#define INTR_EXT   0
+#define INTR_APIC   1
+#define INTR_LAPIC  2
+
+#define VL_STATE_EOI    1
+#define VL_STATE_EXT_LOCK   2
+#define VL_STATE_MSG_LOCK   3
+#define VL_STATE_EOI_LOCK   3
+
+#define VLOCAL_APIC_MAX_INTS             256
+#define VLAPIC_INT_COUNT                (VLOCAL_APIC_MAX_INTS/(BITS_PER_BYTE * 
sizeof(u64)))
+#define VLAPIC_INT_COUNT_32             (VLOCAL_APIC_MAX_INTS/(BITS_PER_BYTE * 
sizeof(u32)))
+
+struct vapic_bus_message{
+   u8   deliv_mode:4;   /* deliver mode, including fixed, LPRI, etc */
+   u8   level:1;        /* level or edge */
+   u8   trig_mod:1;    /* assert or disassert */
+   u8   reserved:2;
+   u8   vector;
+};
+
+typedef struct {
+    /* interrupt for PIC and ext type IOAPIC interrupt */
+    u64   vl_ext_intr[VLAPIC_INT_COUNT];
+    u64   vl_ext_intr_mask[VLAPIC_INT_COUNT];
+    u64   vl_apic_intr[VLAPIC_INT_COUNT];
+    u64   vl_apic_tmr[VLAPIC_INT_COUNT];
+    u64   vl_eoi[VLAPIC_INT_COUNT];
+    u32   vl_lapic_id;
+    u32   direct_intr;
+    u32   vl_apr;
+    u32   vl_logical_dest;
+    u32   vl_dest_format;
+    u32   vl_arb_id;
+    u32   vl_state;
+    u32   apic_msg_count;
+    struct vapic_bus_message  vl_apic_msg[24];
+} vlapic_info;
+
+#endif /* _VMX_VLAPIC_H_ */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH][8/10] Infrastructure for interrupt handling., Arun Sharma <=