Well, it *almost* builds. What happened to core_id?
authorRonald G. Minnich <rminnich@google.com>
Sat, 1 Mar 2014 02:13:56 +0000 (18:13 -0800)
committerRonald G. Minnich <rminnich@google.com>
Sat, 1 Mar 2014 02:13:56 +0000 (18:13 -0800)
Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/arch/x86/Kbuild
kern/arch/x86/apic.h
kern/arch/x86/apic9.c [new file with mode: 0644]
kern/arch/x86/io.h
kern/arch/x86/ioapic.c
kern/arch/x86/ioapic.h
kern/arch/x86/mpacpi.c
kern/arch/x86/rdtsc_test.c

index b97549a..c41cb88 100644 (file)
@@ -1,4 +1,5 @@
 obj-y                                          += apic.o
+obj-y                                          += apic9.o
 obj-y                                          += colored_caches.o
 obj-y                                          += console.o
 obj-y                                          += cpuinfo.o
index 8533d80..d096c51 100644 (file)
  * Functions and definitions for dealing with the APIC and PIC, specific to
  * Intel.  Does not handle an x2APIC.
  */
-
 #include <arch/mmu.h>
 #include <arch/x86.h>
-#include <arch/ioapic.h>
+#include <atomic.h>
 
 /* PIC (8259A)
  * When looking at the specs, A0 is our CMD line, and A1 is the DATA line.  This
@@ -327,10 +326,12 @@ static inline void __send_nmi(uint8_t hw_coreid)
  */
 
 struct ioapic {
-       // include hell. spinlock_t lock;                                       /* IOAPIC: register access */
+       spinlock_t lock;                                        /* IOAPIC: register access */
        uint32_t*       addr;                           /* IOAPIC: register base */
+       uintptr_t paddr;                        /* register base */
        int     nrdt;                           /* IOAPIC: size of RDT */
        int     gsib;                           /* IOAPIC: global RDT index */
+       int     ibase;                          /* global interrupt base */
 };
 
 struct lapic {
@@ -346,7 +347,7 @@ struct lapic {
        int64_t div;
 };
 
-struct Apic {
+struct apic {
        int     useable;                        /* en */
        struct ioapic;
        struct lapic;
@@ -400,6 +401,8 @@ extern      struct apic     xioapic[Napic];
 #define        l32get(p)       (((uint32_t)l16get(p+2)<<16)|l16get(p))
 #define        l64get(p)       (((uint64_t)l32get(p+4)<<32)|l32get(p))
 
+#include <arch/ioapic.h>
+
 extern void apicdump(void);
 extern void apictimerenab(void);
 extern void ioapicdump(void);
diff --git a/kern/arch/x86/apic9.c b/kern/arch/x86/apic9.c
new file mode 100644 (file)
index 0000000..19a396d
--- /dev/null
@@ -0,0 +1,431 @@
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+enum {                                         /* Local APIC registers */
+       Id              = 0x0020,               /* Identification */
+       Ver             = 0x0030,               /* Version */
+       Tp              = 0x0080,               /* Task Priority */
+       Ap              = 0x0090,               /* Arbitration Priority */
+       Pp              = 0x00a0,               /* Processor Priority */
+       Eoi             = 0x00b0,               /* EOI */
+       Ld              = 0x00d0,               /* Logical Destination */
+       Df              = 0x00e0,               /* Destination Format */
+       Siv             = 0x00f0,               /* Spurious Interrupt Vector */
+       Is              = 0x0100,               /* Interrupt Status (8) */
+       Tm              = 0x0180,               /* Trigger Mode (8) */
+       Ir              = 0x0200,               /* Interrupt Request (8) */
+       Es              = 0x0280,               /* Error Status */
+       Iclo            = 0x0300,               /* Interrupt Command */
+       Ichi            = 0x0310,               /* Interrupt Command [63:32] */
+       Lvt0            = 0x0320,               /* Local Vector Table 0 */
+       Lvt5            = 0x0330,               /* Local Vector Table 5 */
+       Lvt4            = 0x0340,               /* Local Vector Table 4 */
+       Lvt1            = 0x0350,               /* Local Vector Table 1 */
+       Lvt2            = 0x0360,               /* Local Vector Table 2 */
+       Lvt3            = 0x0370,               /* Local Vector Table 3 */
+       Tic             = 0x0380,               /* Timer Initial Count */
+       Tcc             = 0x0390,               /* Timer Current Count */
+       Tdc             = 0x03e0,               /* Timer Divide Configuration */
+
+       Tlvt            = Lvt0,                 /* Timer */
+       Lint0           = Lvt1,                 /* Local Interrupt 0 */
+       Lint1           = Lvt2,                 /* Local Interrupt 1 */
+       Elvt            = Lvt3,                 /* Error */
+       Pclvt           = Lvt4,                 /* Performance Counter */
+       Tslvt           = Lvt5,                 /* Thermal Sensor */
+};
+
+enum {                                         /* Siv */
+       Swen            = 0x00000100,           /* Software Enable */
+       Fdis            = 0x00000200,           /* Focus Disable */
+};
+
+enum {                                         /* Iclo */
+       Lassert         = 0x00004000,           /* Assert level */
+
+       DSnone          = 0x00000000,           /* Use Destination Field */
+       DSself          = 0x00040000,           /* Self is only destination */
+       DSallinc        = 0x00080000,           /* All including self */
+       DSallexc        = 0x000c0000,           /* All Excluding self */
+};
+
+enum {                                         /* Tlvt */
+       Periodic        = 0x00020000,           /* Periodic Timer Mode */
+};
+
+enum {                                         /* Tdc */
+       DivX2           = 0x00000000,           /* Divide by 2 */
+       DivX4           = 0x00000001,           /* Divide by 4 */
+       DivX8           = 0x00000002,           /* Divide by 8 */
+       DivX16          = 0x00000003,           /* Divide by 16 */
+       DivX32          = 0x00000008,           /* Divide by 32 */
+       DivX64          = 0x00000009,           /* Divide by 64 */
+       DivX128         = 0x0000000a,           /* Divide by 128 */
+       DivX1           = 0x0000000b,           /* Divide by 1 */
+};
+
+static uint8_t* apicbase;
+static int apmachno = 1;
+
+struct apic    xlapic[Napic];
+
+static uint32_t
+apicrget(int r)
+{
+       if (! apicbase)
+               panic("apicrget: no apic");
+       return *((uint32_t*)(apicbase+r));
+}
+
+static void
+apicrput(int r, uint32_t data)
+{
+       if (! apicbase)
+               panic("apicrput: no apic");
+       *((uint32_t*)(apicbase+r)) = data;
+}
+
+int
+apiceoi(int vecno)
+{
+       apicrput(Eoi, 0);
+
+       return vecno;
+}
+
+int
+apicisr(int vecno)
+{
+       int isr;
+
+       isr = apicrget(Is + (vecno/32)*16);
+
+       return isr & (1<<(vecno%32));
+}
+
+void
+apicinit(int apicno, uintptr_t pa, int isbp)
+{
+       struct apic *apic;
+
+       /*
+        * Mark the APIC useable if it has a good ID
+        * and the registers can be mapped.
+        * The APIC Extended Broadcast and ID bits in the HyperTransport
+        * Transaction Control register determine whether 4 or 8 bits
+        * are used for the APIC ID. There is also xAPIC and x2APIC
+        * to be dealt with sometime.
+        */
+       printk("apicinit: apicno %d pa %#p isbp %d\n", apicno, pa, isbp);
+       if(apicno >= Napic){
+               printd("apicinit%d: out of range\n", apicno);
+               return;
+       }
+       if((apic = &xlapic[apicno])->useable){
+               printd("apicinit%d: already initialised\n", apicno);
+               return;
+       }
+       if(apicbase == NULL){
+               if((apicbase = KADDR(pa)) == NULL){
+                       printd("apicinit%d: can't map apicbase\n", apicno);
+                       return;
+               }
+               printk("apicinit%d: apicbase %#p -> %#p\n", apicno, pa, apicbase);
+       }
+       apic->useable = 1;
+
+       /*
+        * Assign a machno to the processor associated with this
+        * APIC, it may not be an identity map.
+        * Machno 0 is always the bootstrap processor.
+
+       if(isbp){
+               apic->machno = 0;
+               m->apicno = apicno;
+       }
+       else
+               apic->machno = apmachno++;
+        */
+}
+#if 0
+static void
+apicdump0(struct apic *apic, int i)
+{
+       if(!apic->useable || apic->addr != 0)
+               return;
+       printk("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n",
+               i, apic->machno, apic->lvt[0], apic->lvt[1]);
+       printk(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n",
+               apicrget(Tslvt), apicrget(Pclvt), apicrget(Elvt));
+       printk(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n",
+               apicrget(Tlvt), apicrget(Lint0),
+               apicrget(Lint1), apicrget(Siv));
+}
+
+void
+apicdump(void)
+{
+       int i;
+
+       if(!2)
+               return;
+
+       printk("apicbase %#p apmachno %d\n", apicbase, apmachno);
+       for(i = 0; i < Napic; i++)
+               apicdump0(xlapic + i, i);
+       for(i = 0; i < Napic; i++)
+               apicdump0(xioapic + i, i);
+}
+
+static void
+apictimer(Ureg* ureg, void*)
+{
+       timerintr(ureg, 0);
+}
+
+int
+apiconline(void)
+{
+       struct apic *apic;
+       uint64_t tsc;
+       uint32_t dfr, ver;
+       int apicno, nlvt;
+
+       if(apicbase == NULL)
+               return 0;
+       if((apicno = ((apicrget(Id)>>24) & 0xff)) >= Napic)
+               return 0;
+       apic = &xlapic[apicno];
+       if(!apic->useable || apic->addr != NULL)
+               return 0;
+
+       /*
+        * Things that can only be done when on the processor
+        * owning the APIC, apicinit above runs on the bootstrap
+        * processor.
+        */
+       ver = apicrget(Ver);
+       nlvt = ((ver>>16) & 0xff) + 1;
+       if(nlvt > ARRAY_SIZE(apic->lvt)){
+               printd("apicinit%d: nlvt %d > max (%d)\n",
+                       apicno, nlvt, ARRAY_SIZE(apic->lvt));
+               nlvt = ARRAY_SIZE(apic->lvt);
+       }
+       apic->nlvt = nlvt;
+       apic->ver = ver & 0xff;
+
+       /*
+        * These don't really matter in Physical mode;
+        * set the defaults anyway.
+        */
+       if(memcmp(m->cpuinfo, "AuthenticAMD", 12) == 0)
+               dfr = 0xf0000000;
+       else
+               dfr = 0xffffffff;
+       apicrput(Df, dfr);
+       apicrput(Ld, 0x00000000);
+
+       /*
+        * Disable interrupts until ready by setting the Task Priority
+        * register to 0xff.
+        */
+       apicrput(Tp, 0xff);
+
+       /*
+        * Software-enable the APIC in the Spurious Interrupt Vector
+        * register and set the vector number. The vector number must have
+        * bits 3-0 0x0f unless the Extended Spurious Vector Enable bit
+        * is set in the HyperTransport Transaction Control register.
+        */
+       apicrput(Siv, Swen|IdtSPURIOUS);
+
+       /*
+        * Acknowledge any outstanding interrupts.
+        */
+       apicrput(Eoi, 0);
+
+       /*
+        * Use the TSC to determine the APIC timer frequency.
+        * It might be possible to snarf this from a chipset
+        * register instead.
+        */
+       apicrput(Tdc, DivX1);
+       apicrput(Tlvt, Im);
+       tsc = rdtsc() + m->cpuhz/10;
+       apicrput(Tic, 0xffffffff);
+
+       while(rdtsc() < tsc)
+               ;
+
+       apic->hz = (0xffffffff-apicrget(Tcc))*10;
+       apic->max = apic->hz/HZ;
+       apic->min = apic->hz/(100*HZ);
+       apic->div = ((m->cpuhz/apic->max)+HZ/2)/HZ;
+
+       if(m->machno == 0 || 2){
+               printd("apic%d: hz %lld max %lld min %lld div %lld\n", apicno,
+                       apic->hz, apic->max, apic->min, apic->div);
+       }
+
+       /*
+        * Mask interrupts on Performance Counter overflow and
+        * Thermal Sensor if implemented, and on Lintr0 (Legacy INTR),
+        * and Lintr1 (Legacy NMI).
+        * Clear any Error Status (write followed by read) and enable
+        * the Error interrupt.
+        */
+       switch(apic->nlvt){
+       case 6:
+               apicrput(Tslvt, Im);
+               /*FALLTHROUGH*/
+       case 5:
+               apicrput(Pclvt, Im);
+               /*FALLTHROUGH*/
+       default:
+               break;
+       }
+       apicrput(Lint1, apic->lvt[1]|Im|IdtLINT1);
+       apicrput(Lint0, apic->lvt[0]|Im|IdtLINT0);
+
+       apicrput(Es, 0);
+       apicrget(Es);
+       apicrput(Elvt, IdtERROR);
+
+       /*
+        * Issue an INIT Level De-Assert to synchronise arbitration ID's.
+        * (Necessary in this implementation? - not if Pentium 4 or Xeon
+        * (APIC Version >= 0x14), or AMD).
+       apicrput(Ichi, 0);
+       apicrput(Iclo, DSallinc|Lassert|MTir);
+       while(apicrget(Iclo) & Ds)
+               ;
+        */
+
+       /*
+        * Reload the timer to de-synchronise the processors,
+        * then lower the task priority to allow interrupts to be
+        * accepted by the APIC.
+        */
+       microdelay((TK2MS(1)*1000/apmachno) * m->machno);
+
+       if(apic->machno == 0){
+               apicrput(Tic, apic->max);
+               intrenable(IdtTIMER, apictimer, 0, -1, "APIC timer");
+               apicrput(Tlvt, Periodic|IrqTIMER);
+       }
+
+       if(m->machno == 0)
+               apicrput(Tp, 0);
+
+       xlapicmachptr[apicno] = m;
+
+       return 1;
+}
+
+/* To start timers on TCs as part of the boot process. */
+void
+apictimerenab(void)
+{
+       struct apic *apic;
+
+       apic = &xlapic[(apicrget(Id)>>24) & 0xff];
+
+       apiceoi(IdtTIMER);
+       apicrput(Tic, apic->max);
+       apicrput(Tlvt, Periodic|IrqTIMER);
+
+}
+
+void
+apictimerset(uint64_t next)
+{
+       Mpl pl;
+       struct apic *apic;
+       int64_t period;
+
+       apic = &xlapic[(apicrget(Id)>>24) & 0xff];
+
+       pl = splhi();
+       spin_lock(&(&m->apictimerlock)->lock);
+
+       period = apic->max;
+       if(next != 0){
+               period = next - fastticks(NULL);        /* fastticks is just rdtsc() */
+               period /= apic->div;
+
+               if(period < apic->min)
+                       period = apic->min;
+               else if(period > apic->max - apic->min)
+                       period = apic->max;
+       }
+       apicrput(Tic, period);
+
+       spin_unlock(&(&m->apictimerlock)->lock);
+       splx(pl);
+}
+
+void
+apicsipi(int apicno, uintptr_t pa)
+{
+       int i;
+       uint32_t crhi, crlo;
+
+       /*
+        * SIPI - Start-up IPI.
+        * To do: checks on apic validity.
+        */
+       crhi = apicno<<24;
+       apicrput(Ichi, crhi);
+       apicrput(Iclo, DSnone|TMlevel|Lassert|MTir);
+       microdelay(200);
+       apicrput(Iclo, DSnone|TMlevel|MTir);
+       millidelay(10);
+
+       crlo = DSnone|TMedge|MTsipi|((uint32_t)pa/(4*KiB));
+       for(i = 0; i < 2; i++){
+               apicrput(Ichi, crhi);
+               apicrput(Iclo, crlo);
+               microdelay(200);
+       }
+}
+
+void
+apicipi(int apicno)
+{
+       apicrput(Ichi, apicno<<24);
+       apicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI);
+       while(apicrget(Iclo) & Ds)
+               ;
+}
+
+void
+apicpri(int pri)
+{
+       apicrput(Tp, pri);
+}
+#endif
index 5e79be2..4ec4cec 100644 (file)
@@ -67,34 +67,34 @@ enum {
        IdtMAX          = 255,
 };
 
-typedef struct Vkey {
+struct Vkey {
        int     tbdf;                   /* pci: ioapic or msi sources */
        int     irq;                    /* 8259-emulating sources */
-} Vkey;
+};
 
 typedef struct Vctl {
-       Vctl*   next;                   /* handlers on this vector */
+       struct Vctl*    next;                   /* handlers on this vector */
 
        int     isintr;                 /* interrupt or fault/trap */
 
-       Vkey;                           /* source-specific key; tbdf for pci */
-       void    (*f)(Ureg*, void*);     /* handler to call */
+       struct Vkey;                            /* source-specific key; tbdf for pci */
+       //void  (*f)(Ureg*, void*);     /* handler to call */
        void*   a;                      /* argument to call it with */
        char    name[KNAMELEN];         /* of driver */
        char    *type;
 
        int     (*isr)(int);            /* get isr bit for this irq */
        int     (*eoi)(int);            /* eoi */
-       int     (*mask)(Vkey*, int);    /* interrupt enable returns masked vector */
+       int     (*mask)(struct Vkey*, int);     /* interrupt enable returns masked vector */
        int     vno;
 } Vctl;
 
-typedef struct ACVctl {
-       char*   (*f)(Ureg*,void*);
+struct ACVctl {
+       //char* (*f)(Ureg*,void*);
        void*   a;
        int     vno;
        char    name[KNAMELEN];         /* of driver */
-} ACVctl;
+};
 
 enum {
        BusCBUS         = 0,            /* Corollary CBUS */
@@ -270,16 +270,14 @@ enum {
        PciCapSATA      = 0x12,
        PciCapHSW       = 0x0c,         /* hot swap */
 };
-
-typedef struct Pcisiz Pcisiz;
+#if 0
 struct Pcisiz
 {
-       Pcidev* dev;
+//     Pcidev* dev;
        int     siz;
        int     bar;
 };
 
-typedef struct Pcidev Pcidev;
 struct Pcidev
 {
        int     tbdf;                   /* type+bus+device+function */
@@ -315,10 +313,9 @@ struct Pcidev
                int     size;
        } ioa, mema;
 };
-
+#endif
 #define PCIWINDOW      0
 #define PCIWADDR(va)   (PADDR(va)+PCIWINDOW)
 #define ISAWINDOW      0
 #define ISAWADDR(va)   (PADDR(va)+ISAWINDOW)
 
-#pragma        varargck        type    "T"     int
index a71b1e2..d4d256a 100644 (file)
@@ -132,7 +132,7 @@ ioapicintrinit(int busno, int apicno, int intin, int devno, uint32_t lo)
 }
 
 void
-ioapicinit(int id, int ibase, uintptr_t_t pa)
+ioapicinit(int id, int ibase, uintptr_t pa)
 {
        struct apic *apic;
        static int base;
@@ -145,7 +145,7 @@ ioapicinit(int id, int ibase, uintptr_t_t pa)
                return;
 
        apic = &xioapic[id];
-       if(apic->useable || (apic->addr = vmap(pa, 1024)) == NULL)
+       if(apic->useable || (apic->addr = KADDR(pa)/*vmap(pa, 1024)*/) == NULL)
                return;
        apic->useable = 1;
        apic->paddr = pa;
@@ -225,7 +225,7 @@ ioapiconline(void)
 }
 
 static int dfpolicy = 0;
-
+#if 0
 static void
 ioapicintrdd(uint32_t* hi, uint32_t* lo)
 {
@@ -272,7 +272,7 @@ ioapicintrdd(uint32_t* hi, uint32_t* lo)
                        if(xlapic[i].useable && xlapic[i].addr == 0)
                                break;
                }
-               spin_unlock(&(&dflock)->lock);
+               spin_unlock(&dflock->lock);
 
                *hi = i<<24;
                break;
@@ -285,12 +285,12 @@ nextvec(void)
 {
        unsigned int vecno;
 
-       spin_lock(&(&idtnolock)->lock);
+       spin_lock(&idtnolock->lock);
        vecno = idtno;
        idtno = (idtno+8) % IdtMAX;
        if(idtno < IdtIOAPIC)
                idtno += IdtIOAPIC;
-       spin_unlock(&(&idtnolock)->lock);
+       spin_unlock(&idtnolock->lock);
 
        return vecno;
 }
@@ -495,3 +495,4 @@ ioapicintrdisable(int vecno)
 
        return 0;
 }
+#endif
index 87733ac..c1c98a7 100644 (file)
@@ -9,38 +9,8 @@
 
 #ifndef ROS_KERN_IOAPIC_H
 #define ROS_KERN_IOAPIC_H
-struct bus {
-       uint8_t type;
-       uint8_t busno;
-       uint8_t po;
-       uint8_t el;
-
-       struct aintr*   aintr;                  /* interrupts tied to this bus */
-       struct bus*     next;
-};
-
-struct aintr {
-       // no idea yet. PCMPintr* intr;
-       struct apic*    apic;
-       struct aintr*   next;
-};
-
-struct apic {
-       int     useable;
-       int     type;
-       int     apicno;
-       uint32_t*       addr;                   /* register base address */
-       uint32_t        paddr;
-       int     flags;                  /* PcmpBP|PcmpEN */
-
-       //spinlock_t lock;              /* I/O APIC: register access */
-       int     mre;                    /* I/O APIC: maximum redirection entry */
-
-       int     lintr[2];               /* Local APIC */
-       int     machno;
-
-       int     online;
-};
+#include <atomic.h>
+#include <arch/apic.h>
 
 enum {
        MaxAPICNO       = 254,          /* 255 is physical broadcast */
@@ -83,7 +53,7 @@ enum {
        IOAPIC_PBASE    = 0xfec00000, /* default *physical* address */
 };
 
-extern void ioapicinit(struct apic*, int);
+extern void ioapicinit(int id, int ibase, uintptr_t pa);
 extern void ioapicrdtr(struct apic*, int unused_int, int*, int*);
 extern void ioapicrdtw(struct apic*, int unused_int, int, int);
 
index d02562c..ef50dbd 100644 (file)
@@ -44,7 +44,9 @@ mpacpi(int ncleft)
                        }
                        else if(ncleft != 0){
                                ncleft--;
-                               apicinit(st->lapic.id, apics->lapicpa, bp);
+#warning "not calling fictitions acpiinit"
+                               printk("apicinit(%d, %p, %d);\n", st->lapic.id, apics->lapicpa, bp);
+                               //apicinit(st->lapic.id, apics->lapicpa, bp);
                        } else
                                already = "(off)";
 
index 414d3f7..fe733ac 100644 (file)
@@ -754,7 +754,8 @@ void test_tsc_cycles(void)
                                      : : : "eax", "cc");
        }
        end = read_tsc_serialized();
-       end = end - start - system_timing.timing_overhead;
+# warning "what happened to system_timing?"
+       end = end - start - 0; //system_timing.timing_overhead;
        printk("%llu (100,000) ticks passed, run twice to load the icache\n", end);
 
        enable_irqsave(&irq_state);