X86: Put in initial implementation of the local APIC.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 27 Feb 2008 04:39:53 +0000 (23:39 -0500)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 27 Feb 2008 04:39:53 +0000 (23:39 -0500)
--HG--
extra : convert_revision : 1708a93d96b819e64ed456c75dbb5325ac8114a8

src/arch/x86/miscregfile.cc
src/arch/x86/miscregs.hh
src/arch/x86/mmaped_ipr.hh
src/arch/x86/tlb.cc
src/arch/x86/tlb.hh
src/arch/x86/utility.cc

index 153610e447e8173e24a13893218aa48380c4b9a9..3b4dc3407a5d933a3c98592c006bd38b7d4ce8ff 100644 (file)
@@ -123,6 +123,84 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg)
 
 MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc)
 {
+    if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) {
+        if (miscReg >= MISCREG_APIC_IN_SERVICE(0) &&
+                miscReg <= MISCREG_APIC_IN_SERVICE(15)) {
+            panic("Local APIC In-Service registers are unimplemented.\n");
+        }
+        if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) &&
+                miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) {
+            panic("Local APIC Trigger Mode registers are unimplemented.\n");
+        }
+        if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) &&
+                miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) {
+            panic("Local APIC Interrupt Request registers "
+                    "are unimplemented.\n");
+        }
+        switch (miscReg) {
+          case MISCREG_APIC_TASK_PRIORITY:
+            panic("Local APIC Task Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_ARBITRATION_PRIORITY:
+            panic("Local APIC Arbitration Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_PROCESSOR_PRIORITY:
+            panic("Local APIC Processor Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_EOI:
+            panic("Local APIC EOI register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LOGICAL_DESTINATION:
+            panic("Local APIC Logical Destination register unimplemented.\n");
+            break;
+          case MISCREG_APIC_DESTINATION_FORMAT:
+            panic("Local APIC Destination Format register unimplemented.\n");
+            break;
+          case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR:
+            panic("Local APIC Spurious Interrupt Vector"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_ERROR_STATUS:
+            panic("Local APIC Error Status register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INTERRUPT_COMMAND_LOW:
+            panic("Local APIC Interrupt Command low"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INTERRUPT_COMMAND_HIGH:
+            panic("Local APIC Interrupt Command high"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_TIMER:
+            panic("Local APIC LVT Timer register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_THERMAL_SENSOR:
+            panic("Local APIC LVT Thermal Sensor register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
+            panic("Local APIC LVT Performance Monitoring Counters"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_LINT0:
+            panic("Local APIC LVT LINT0 register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_LINT1:
+            panic("Local APIC LVT LINT1 register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_ERROR:
+            panic("Local APIC LVT Error register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INITIAL_COUNT:
+            panic("Local APIC Initial Count register unimplemented.\n");
+            break;
+          case MISCREG_APIC_CURRENT_COUNT:
+            panic("Local APIC Current Count register unimplemented.\n");
+            break;
+          case MISCREG_APIC_DIVIDE_COUNT:
+            panic("Local APIC Divide Count register unimplemented.\n");
+            break;
+        }
+    }
     return readRegNoEffect(miscReg);
 }
 
@@ -143,6 +221,92 @@ void MiscRegFile::setReg(int miscReg,
         const MiscReg &val, ThreadContext * tc)
 {
     MiscReg newVal = val;
+    if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) {
+        if (miscReg >= MISCREG_APIC_IN_SERVICE(0) &&
+                miscReg <= MISCREG_APIC_IN_SERVICE(15)) {
+            panic("Local APIC In-Service registers are unimplemented.\n");
+        }
+        if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) &&
+                miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) {
+            panic("Local APIC Trigger Mode registers are unimplemented.\n");
+        }
+        if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) &&
+                miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) {
+            panic("Local APIC Interrupt Request registers "
+                    "are unimplemented.\n");
+        }
+        switch (miscReg) {
+          case MISCREG_APIC_ID:
+            panic("Local APIC ID register unimplemented.\n");
+            break;
+          case MISCREG_APIC_VERSION:
+            panic("Local APIC Version register is read only.\n");
+            break;
+          case MISCREG_APIC_TASK_PRIORITY:
+            panic("Local APIC Task Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_ARBITRATION_PRIORITY:
+            panic("Local APIC Arbitration Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_PROCESSOR_PRIORITY:
+            panic("Local APIC Processor Priority register unimplemented.\n");
+            break;
+          case MISCREG_APIC_EOI:
+            panic("Local APIC EOI register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LOGICAL_DESTINATION:
+            panic("Local APIC Logical Destination register unimplemented.\n");
+            break;
+          case MISCREG_APIC_DESTINATION_FORMAT:
+            panic("Local APIC Destination Format register unimplemented.\n");
+            break;
+          case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR:
+            panic("Local APIC Spurious Interrupt Vector"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_ERROR_STATUS:
+            panic("Local APIC Error Status register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INTERRUPT_COMMAND_LOW:
+            panic("Local APIC Interrupt Command low"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INTERRUPT_COMMAND_HIGH:
+            panic("Local APIC Interrupt Command high"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_TIMER:
+            panic("Local APIC LVT Timer register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_THERMAL_SENSOR:
+            panic("Local APIC LVT Thermal Sensor register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
+            panic("Local APIC LVT Performance Monitoring Counters"
+                    " register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_LINT0:
+            panic("Local APIC LVT LINT0 register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_LINT1:
+            panic("Local APIC LVT LINT1 register unimplemented.\n");
+            break;
+          case MISCREG_APIC_LVT_ERROR:
+            panic("Local APIC LVT Error register unimplemented.\n");
+            break;
+          case MISCREG_APIC_INITIAL_COUNT:
+            panic("Local APIC Initial Count register unimplemented.\n");
+            break;
+          case MISCREG_APIC_CURRENT_COUNT:
+            panic("Local APIC Current Count register unimplemented.\n");
+            break;
+          case MISCREG_APIC_DIVIDE_COUNT:
+            panic("Local APIC Divide Count register unimplemented.\n");
+            break;
+        }
+        setRegNoEffect(miscReg, newVal);
+        return;
+    }
     switch(miscReg)
     {
       case MISCREG_CR0:
index 2bf647150a1b860e1a0aa1432444a2381adfacdb..d1016d2a99ee0b0636ba317feed8059e353c936f 100644 (file)
@@ -339,6 +339,41 @@ namespace X86ISA
 
         //XXX Add "Model-Specific Registers"
 
+        MISCREG_APIC_BASE,
+
+        MISCREG_APIC_START,
+        MISCREG_APIC_ID = MISCREG_APIC_START,
+        MISCREG_APIC_VERSION,
+        MISCREG_APIC_TASK_PRIORITY,
+        MISCREG_APIC_ARBITRATION_PRIORITY,
+        MISCREG_APIC_PROCESSOR_PRIORITY,
+        MISCREG_APIC_EOI,
+        MISCREG_APIC_LOGICAL_DESTINATION,
+        MISCREG_APIC_DESTINATION_FORMAT,
+        MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR,
+
+        MISCREG_APIC_IN_SERVICE_BASE,
+
+        MISCREG_APIC_TRIGGER_MODE_BASE = MISCREG_APIC_IN_SERVICE_BASE + 16,
+
+        MISCREG_APIC_INTERRUPT_REQUEST_BASE =
+            MISCREG_APIC_TRIGGER_MODE_BASE + 16,
+
+        MISCREG_APIC_ERROR_STATUS = MISCREG_APIC_INTERRUPT_REQUEST_BASE + 16,
+        MISCREG_APIC_INTERRUPT_COMMAND_LOW,
+        MISCREG_APIC_INTERRUPT_COMMAND_HIGH,
+        MISCREG_APIC_LVT_TIMER,
+        MISCREG_APIC_LVT_THERMAL_SENSOR,
+        MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS,
+        MISCREG_APIC_LVT_LINT0,
+        MISCREG_APIC_LVT_LINT1,
+        MISCREG_APIC_LVT_ERROR,
+        MISCREG_APIC_INITIAL_COUNT,
+        MISCREG_APIC_CURRENT_COUNT,
+        MISCREG_APIC_DIVIDE_COUNT,
+        MISCREG_APIC_END = MISCREG_APIC_DIVIDE_COUNT,
+
+        // "Fake" MSRs for internally implemented devices
         MISCREG_PCI_CONFIG_ADDRESS,
 
         NUM_MISCREGS
@@ -446,6 +481,24 @@ namespace X86ISA
         return (MiscRegIndex)(MISCREG_SEG_ATTR_BASE + index);
     }
 
+    static inline MiscRegIndex
+    MISCREG_APIC_IN_SERVICE(int index)
+    {
+        return (MiscRegIndex)(MISCREG_APIC_IN_SERVICE_BASE + index);
+    }
+
+    static inline MiscRegIndex
+    MISCREG_APIC_TRIGGER_MODE(int index)
+    {
+        return (MiscRegIndex)(MISCREG_APIC_TRIGGER_MODE_BASE + index);
+    }
+
+    static inline MiscRegIndex
+    MISCREG_APIC_INTERRUPT_REQUEST(int index)
+    {
+        return (MiscRegIndex)(MISCREG_APIC_INTERRUPT_REQUEST_BASE + index);
+    }
+
     /**
      * A type to describe the condition code bits of the RFLAGS register,
      * plus two flags, EZF and ECF, which are only visible to microcode.
@@ -794,6 +847,16 @@ namespace X86ISA
      */
     BitUnion64(TR)
     EndBitUnion(TR)
+
+
+    /**
+     * Local APIC Base Register
+     */
+    BitUnion64(LocalApicBase)
+        Bitfield<51, 12> base;
+        Bitfield<11> enable;
+        Bitfield<8> bsp;
+    EndBitUnion(LocalApicBase)
 };
 
 #endif // __ARCH_X86_INTREGS_HH__
index 36c0baacae419b7a0e38ce088fbf51df9bee3afa..eda85c08448000024679334a150429d32563b6f6 100644 (file)
@@ -78,7 +78,15 @@ namespace X86ISA
 #if !FULL_SYSTEM
         panic("Shouldn't have a memory mapped register in SE\n");
 #else
-        pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg)));
+        MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg));
+        if (index == MISCREG_PCI_CONFIG_ADDRESS ||
+                (index >= MISCREG_APIC_START &&
+                 index <= MISCREG_APIC_END)) {
+            pkt->set((uint32_t)(xc->readMiscReg(pkt->getAddr() /
+                            sizeof(MiscReg))));
+        } else {
+            pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg)));
+        }
 #endif
         return xc->getCpuPtr()->ticks(1);
     }
@@ -90,7 +98,9 @@ namespace X86ISA
         panic("Shouldn't have a memory mapped register in SE\n");
 #else
         MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg));
-        if (index == MISCREG_PCI_CONFIG_ADDRESS) {
+        if (index == MISCREG_PCI_CONFIG_ADDRESS ||
+                (index >= MISCREG_APIC_START &&
+                 index <= MISCREG_APIC_END)) {
             xc->setMiscReg(index, gtoh(pkt->get<uint32_t>()));
         } else {
             xc->setMiscReg(pkt->getAddr() / sizeof(MiscReg),
index ae8fcf9bea4c3c8e6baaf8785e8744e1c6b56e32..a87abf2122f7d3d0b72e94421113311c760e51e5 100644 (file)
@@ -108,8 +108,8 @@ TLB::insert(Addr vpn, TlbEntry &entry)
     entryList.push_front(newEntry);
 }
 
-TlbEntry *
-TLB::lookup(Addr va, bool update_lru)
+TLB::EntryList::iterator
+TLB::lookupIt(Addr va, bool update_lru)
 {
     //TODO make this smarter at some point
     EntryList::iterator entry;
@@ -117,15 +117,25 @@ TLB::lookup(Addr va, bool update_lru)
         if ((*entry)->vaddr <= va && (*entry)->vaddr + (*entry)->size > va) {
             DPRINTF(TLB, "Matched vaddr %#x to entry starting at %#x "
                     "with size %#x.\n", va, (*entry)->vaddr, (*entry)->size);
-            TlbEntry *e = *entry;
             if (update_lru) {
+                entryList.push_front(*entry);
                 entryList.erase(entry);
-                entryList.push_front(e);
+                entry = entryList.begin();
             }
-            return e;
+            break;
         }
     }
-    return NULL;
+    return entry;
+}
+
+TlbEntry *
+TLB::lookup(Addr va, bool update_lru)
+{
+    EntryList::iterator entry = lookupIt(va, update_lru);
+    if (entry == entryList.end())
+        return NULL;
+    else
+        return *entry;
 }
 
 #if FULL_SYSTEM
@@ -206,6 +216,9 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
               case 0x10:
                 regNum = MISCREG_TSC;
                 break;
+              case 0x1B:
+                regNum = MISCREG_APIC_BASE;
+                break;
               case 0xFE:
                 regNum = MISCREG_MTRRCAP;
                 break;
@@ -578,6 +591,148 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
         DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
         req->setPaddr(vaddr);
     }
+    // Check for an access to the local APIC
+    LocalApicBase localApicBase = tc->readMiscRegNoEffect(MISCREG_APIC_BASE);
+    Addr baseAddr = localApicBase.base << 12;
+    Addr paddr = req->getPaddr();
+    if (baseAddr <= paddr && baseAddr + (1 << 12) > paddr) {
+        req->setMmapedIpr(true);
+        // Check alignment
+        if (paddr & ((32/8) - 1))
+            return new GeneralProtection(0);
+        // Check access size
+        if (req->getSize() != (32/8))
+            return new GeneralProtection(0);
+        MiscReg regNum;
+        switch (paddr - baseAddr)
+        {
+          case 0x20:
+            regNum = MISCREG_APIC_ID;
+            break;
+          case 0x30:
+            regNum = MISCREG_APIC_VERSION;
+            break;
+          case 0x80:
+            regNum = MISCREG_APIC_TASK_PRIORITY;
+            break;
+          case 0x90:
+            regNum = MISCREG_APIC_ARBITRATION_PRIORITY;
+            break;
+          case 0xA0:
+            regNum = MISCREG_APIC_PROCESSOR_PRIORITY;
+            break;
+          case 0xB0:
+            regNum = MISCREG_APIC_EOI;
+            break;
+          case 0xD0:
+            regNum = MISCREG_APIC_LOGICAL_DESTINATION;
+            break;
+          case 0xE0:
+            regNum = MISCREG_APIC_DESTINATION_FORMAT;
+            break;
+          case 0xF0:
+            regNum = MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR;
+            break;
+          case 0x100:
+          case 0x108:
+          case 0x110:
+          case 0x118:
+          case 0x120:
+          case 0x128:
+          case 0x130:
+          case 0x138:
+          case 0x140:
+          case 0x148:
+          case 0x150:
+          case 0x158:
+          case 0x160:
+          case 0x168:
+          case 0x170:
+          case 0x178:
+            regNum = MISCREG_APIC_IN_SERVICE(
+                    (paddr - baseAddr - 0x100) / 0x8);
+            break;
+          case 0x180:
+          case 0x188:
+          case 0x190:
+          case 0x198:
+          case 0x1A0:
+          case 0x1A8:
+          case 0x1B0:
+          case 0x1B8:
+          case 0x1C0:
+          case 0x1C8:
+          case 0x1D0:
+          case 0x1D8:
+          case 0x1E0:
+          case 0x1E8:
+          case 0x1F0:
+          case 0x1F8:
+            regNum = MISCREG_APIC_TRIGGER_MODE(
+                    (paddr - baseAddr - 0x180) / 0x8);
+            break;
+          case 0x200:
+          case 0x208:
+          case 0x210:
+          case 0x218:
+          case 0x220:
+          case 0x228:
+          case 0x230:
+          case 0x238:
+          case 0x240:
+          case 0x248:
+          case 0x250:
+          case 0x258:
+          case 0x260:
+          case 0x268:
+          case 0x270:
+          case 0x278:
+            regNum = MISCREG_APIC_INTERRUPT_REQUEST(
+                    (paddr - baseAddr - 0x200) / 0x8);
+            break;
+          case 0x280:
+            regNum = MISCREG_APIC_ERROR_STATUS;
+            break;
+          case 0x300:
+            regNum = MISCREG_APIC_INTERRUPT_COMMAND_LOW;
+            break;
+          case 0x310:
+            regNum = MISCREG_APIC_INTERRUPT_COMMAND_HIGH;
+            break;
+          case 0x320:
+            regNum = MISCREG_APIC_LVT_TIMER;
+            break;
+          case 0x330:
+            regNum = MISCREG_APIC_LVT_THERMAL_SENSOR;
+            break;
+          case 0x340:
+            regNum = MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
+            break;
+          case 0x350:
+            regNum = MISCREG_APIC_LVT_LINT0;
+            break;
+          case 0x360:
+            regNum = MISCREG_APIC_LVT_LINT1;
+            break;
+          case 0x370:
+            regNum = MISCREG_APIC_LVT_ERROR;
+            break;
+          case 0x380:
+            regNum = MISCREG_APIC_INITIAL_COUNT;
+            break;
+          case 0x390:
+            regNum = MISCREG_APIC_CURRENT_COUNT;
+            break;
+          case 0x3E0:
+            regNum = MISCREG_APIC_DIVIDE_COUNT;
+            break;
+          default:
+            // A reserved register field.
+            return new GeneralProtection(0);
+            break;
+        }
+        req->setPaddr(regNum * sizeof(MiscReg));
+    }
     return NoFault;
 };
 
index f6ccd5731da1b880b6fa6f270602affd6a19a60b..89b965e971177f792d2d567ac2e4d43da445d636 100644 (file)
@@ -90,6 +90,8 @@ namespace X86ISA
         friend class FakeITLBFault;
         friend class FakeDTLBFault;
 
+        typedef std::list<TlbEntry *> EntryList;
+
         bool _allowNX;
         uint32_t configAddress;
 
@@ -108,6 +110,10 @@ namespace X86ISA
 
         void setConfigAddress(uint32_t addr);
 
+      protected:
+
+        EntryList::iterator lookupIt(Addr va, bool update_lru = true);
+
 #if FULL_SYSTEM
       protected:
 
@@ -128,7 +134,6 @@ namespace X86ISA
 
         TlbEntry * tlb;
 
-        typedef std::list<TlbEntry *> EntryList;
         EntryList freeList;
         EntryList entryList;
 
index f5e87b860c2b0ab46899a056cefdb25fcf60141b..5fe5bf8c37983b72f742a88349b9695f942a7962 100644 (file)
@@ -248,6 +248,16 @@ void initCPU(ThreadContext *tc, int cpuId)
     // TODO Turn on the APIC. This should be handled elsewhere but it isn't
     // currently being handled at all.
 
+    LocalApicBase lApicBase = 0;
+    lApicBase.base = 0xFEE00000 >> 12;
+    lApicBase.enable = 1;
+    lApicBase.bsp = (cpuId == 0);
+    tc->setMiscReg(MISCREG_APIC_BASE, lApicBase);
+
+    tc->setMiscRegNoEffect(MISCREG_APIC_ID, cpuId << 24);
+
+    tc->setMiscRegNoEffect(MISCREG_APIC_VERSION, (5 << 16) | 0x14);
+
     // TODO Set the SMRAM base address (SMBASE) to 0x00030000
 
     tc->setMiscReg(MISCREG_VM_CR, 0);