power: Add support for Radix Translation
authorPhanikiran Harithas <phanikiran.harithas@gmail.com>
Sun, 10 Jun 2018 12:15:05 +0000 (17:45 +0530)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 24 Jan 2021 03:57:54 +0000 (03:57 +0000)
Power ISA v3.0 introduces the Radix MMU in addition to the Hash MMU.

This patch adds support in gem5 for handling the Radix based address
translations when MSR[IR,DR] bits are set.

It also adds an example of a radix_walk.

Change-Id: I193f8d44f36b429997f7ffcb788a50544ba65a8c

Signed-off-by: Phanikiran Harithas <phanikiran.harithas@gmail.com>
Signed-off-by: Venkatnarayan Kulkarni <venkatnarayankulkarni@gmail.com>
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
configs/common/Benchmarks.py
configs/common/FSConfig.py
src/arch/power/PowerTLB.py
src/arch/power/SConscript
src/arch/power/isa/decoder.isa
src/arch/power/radix_walk_example.txt [new file with mode: 0644]
src/arch/power/radixwalk.cc [new file with mode: 0644]
src/arch/power/radixwalk.hh [new file with mode: 0644]
src/arch/power/tlb.cc
src/arch/power/tlb.hh
src/cpu/BaseCPU.py

index 8477d77c481e8aee29a28793375477aadfde6409..2800ee64443d54a44f5cca1da9d27a17cb9aebe3 100644 (file)
@@ -55,6 +55,8 @@ class SysConfig:
     def disks(self):
         if self.disknames:
             return [disk(diskname) for diskname in self.disknames]
+        elif buildEnv['TARGET_ISA'] == 'power':
+            return env.get('LINUX_IMAGE', disk('linux-latest.img'))
         else:
             return []
 
index 8896e6707979786db306853d1f88cf4e53776075..01c51eff3c98c6f111d525f6666328c0c710aebc 100644 (file)
@@ -668,7 +668,7 @@ def makeLinuxPowerSystem(mem_mode, numCPUs=1, mdesc=None, cmdline=None):
     self.boot_osflags = fillInCmdline(mdesc, cmdline)
     self.kernel = binary('vmlinux')
     self.dtb_filename = binary('gem5-power9-fs.dtb')
-return self
+    return self
 
 
 def makeDualRoot(full_system, testSystem, driveSystem, dumpfile):
index 7f9a2715b890d596f97055adfb78854f603ffe94..3451c822f650afab0e3dae4cd33541e938159f1e 100644 (file)
 
 from m5.SimObject import SimObject
 from m5.params import *
+from m5.proxy import *
+
+from MemObject import MemObject
+
+class PowerRadixWalk(MemObject):
+    type = 'PowerRadixWalk'
+    cxx_class = 'PowerISA::RadixWalk'
+    cxx_header = 'arch/power/radixwalk.hh'
+    port = MasterPort("Port for the hardware table walker")
+    system = Param.System(Parent.any, "system object")
 
 from m5.objects.BaseTLB import BaseTLB
 
@@ -36,3 +46,5 @@ class PowerTLB(BaseTLB):
     cxx_class = 'PowerISA::TLB'
     cxx_header = 'arch/power/tlb.hh'
     size = Param.Int(64, "TLB size")
+    walker = Param.PowerRadixWalk(\
+            PowerRadixWalk(), "page table walker")
index 1187acf3d653e72a1fdcd0228e26cb1e7bb9d7cc..b1c873615b52e0f00c3fba11c0d72d9d71a35256 100644 (file)
@@ -43,9 +43,12 @@ if env['TARGET_ISA'] == 'power':
     Source('interrupts.cc')
     Source('linux/linux.cc')
     Source('linux/process.cc')
+    Source('linux/system.cc')
     Source('isa.cc')
     Source('pagetable.cc')
     Source('process.cc')
+    Source('radixwalk.cc')
+    Source('system.cc')
     Source('remote_gdb.cc')
     Source('tlb.cc')
     Source('utility.cc')
@@ -53,8 +56,10 @@ if env['TARGET_ISA'] == 'power':
     SimObject('PowerInterrupts.py')
     SimObject('PowerISA.py')
     SimObject('PowerTLB.py')
+    SimObject('PowerSystem.py')
 
     DebugFlag('Power')
+    DebugFlag('RadixWalk')
 
     ISADesc('isa/main.isa')
 
index da2cabe29de2f9de39a18d484c34ce5cdc2180ba..83fc11edd92f6095b8b4f9146f0ff18f889a5c84 100644 (file)
@@ -162,8 +162,11 @@ decode PO default Unknown::unknown() {
         }
     }
 
-    17: IntOp::sc({{ xc->syscall(R0, &fault); }},
-                  [ IsSyscall, IsNonSpeculative, IsSerializeAfter ]);
+    format IntOp {
+        17: sc({{ xc->syscall(R0, &fault); }},
+               [ IsSyscall, IsNonSpeculative, IsSerializeAfter ]);
+        2: tdi({{ }});
+    }
 
     format LoadDispOp {
         34: lbz({{ Rt = Mem_ub; }});
@@ -872,6 +875,12 @@ decode PO default Unknown::unknown() {
             246: dcbtst({{ }});
             598: sync({{ }}, [ IsMemBarrier ]);
             854: eieio({{ }}, [ IsMemBarrier ]);
+            54:  dcbst({{ }});
+            982: icbi({{ }});
+            306: tlbie({{ }});
+            274: tlbiel({{ }});
+            566: tlbsync({{ }});
+            498: slbia({{ }});
         }
 
         // These instructions are of XO form with bit 21 as the OE bit.
diff --git a/src/arch/power/radix_walk_example.txt b/src/arch/power/radix_walk_example.txt
new file mode 100644 (file)
index 0000000..2e6c734
--- /dev/null
@@ -0,0 +1,327 @@
+================ Radix Walk Example =================================
+SPRN_PTCR = 0x10004 : PATB = 0x10, PATS = 0x4
+=====================================================================
+                       Memory Layout
+=====================================================================
+PARTITION_TABLE
+0x10000 : PARTITION_TABLE_1       |        PARTITION_TABLE_2
+         0xc0000000000030ad      |        0x800000000100000b
+          HR=1                             PATB_GR=1
+         RTS1=0x2                         PRTB=0x1000
+         RPDB=0x300                       PRTS=0xb
+         RTS2=0x5
+         RPDS=0xd
+
+RADIX_ROOT
+0x30000 :  RADIX_ROOT_PTE         | RADIX_ROOT_KERNEL_PTE
+          0x8000000000040009     | 0x8000000000040005
+           V = 1                  | V = 1
+          L = 0                  | L = 0
+          NLB = 0x400            | NLB = 0x400
+          NLS = 9                | NLS = 5
+
+RADIX_SECOND_LEVEL
+0x40000 :  RADIX_SECOND_LEVEL_PTE | RADIX_SECOND_LEVEL_KERNEL_PTE
+           0xc000000000000187     | 0x8000000000050004
+          V = 1                  | V = 1
+          L = 1                  | L = 0
+          SW = 0                 | NLB = 0x500
+          RPN = 0                | NLS = 5
+          R = 1
+          C = 1
+          ATT = 0
+          EAA 0x7
+
+RADIX_THIRD_LEVEL
+0x50000:  RADIX_THIRD_LEVEL_KERNEL_PTE
+         0xc000000000000187
+          V = 1
+         L = 1
+         SW = 0
+         RPN = 0
+         R = 1
+         C = 1
+         ATT = 0
+         EAA = 0x7
+
+
+PROCESS_TABLE:
+0x1000000 : PROCESS_TABLE_1       |     PROCESS_TABLE_2 //Hypervisor Kernel
+           0x40000000000300ac    |     0x0
+            RTS1 = 0x2
+           RPDB = 0x300
+           RTS2 = 0x5
+           RPDS = 12
+
+           PROCESS_TABLE_3       |     PROCESS_TABLE_3 //Hypervisor Userspace 
+           0x40000000000300ad    |     0x0
+            RTS1 = 0x2
+           RPDB = 0x300
+           RTS2 = 0x5
+           RPDS = 13
+
+================== Example 1 : Hypervisor Userspace =======================
+MSR[HV] = 1, MSR[PR] = 1
+vaddr = 0x1000 = 0x0000000000001000
+
+PTCR : PATB = 0x10 = Partition Table Base
+       PATS = 0x4  = Partition Table Size
+
+Getting the Partition Table Entry (PATE0 and PATE1)
+
+Partition table base address is obtained by left-shifting
+PATB by 12 bits. Because the Partition table base is always aligned
+to 4k which is also the minimum size of the partition table.
+
+patb_addr = PATB << 12 = 0x10000
+
+effLPID = 0 // HV=1
+
+pate1_offset = 0 * 16 + 8 = 8  // Partition Table second word is PATE1
+                               // for this effLPID
+
+pate1_addr = patb_addr + pate1_offset = 0x10008 = PARTITION_TABLE_2
+From PARTITION_TABLE_2
+PRTB = 0x1000
+
+Process Table Base address is obtained by left-shifting PRTB by 12
+bits. Because the Process table is size aligned and at least is 4k.
+prtb_addr = PRTB << 12 = 0x1000000
+
+effPID = SPRN_PIDR = 1 // HV=1, PR=1, QUADRANT_0b00
+
+prte0_offset = effPID * 16 = 16 //First double word in Process Table
+                                //Indexed by effPID
+prte0_addr = prtb_addr + prte0_offset = 0x1000010 = PROCESS_TABLE_3
+
+------------------ The Walk Begins Now --------------------
+From PROCESS_TABLE_3
+RPDB  = 0x300
+RPDS  = 13
+RTS = RTS1 << 3 | RTS2 = 0x2 << 3 | 5 = 1 << 4 + 5 = 21
+totalSize = RTS + 31 = 21 + 31 = 52 = virtual address space used
+                                      by software
+
+Root Level
+--------------
+nextLevelBase = RPDB << 8 = 0x30000
+nextLevelSize = RPDS = 13
+
+// Call the lower totalSize bits of vaddr as the useful bits.
+// The upper nextLevelSize bits of these useful bits
+// has the index into the Page Table Directory
+// Each entry is 8 bytes.
+shift = totalSize - nextLevelSize = 52 - 13 = 39
+mask = (1 << nextLeveSize) - 1 = 0xFFF
+index = (vaddr >> shift ) & mask = 0
+
+entry_addr = nextLevelBase + index * 8 = 0x30000 + 0 = 0x30000 = RADIX_ROOT_PTE
+
+From RADIX_ROOT_PTE
+V = 1
+L = 0.
+NLB = 0x400
+NLS = 9
+
+So this is a directory. Hence obtain NLB and NLS
+
+First Level
+----------------
+
+// We no longer need the upper nextLevelSize bits
+// of the useful bits. Discard them.
+// Call remaining bits of vaddr as useful bits.
+totalSize = totalSize - nextLevelSize = 52 - 13 = 39
+
+//Recompute the new Page Directory Base and the Size
+nextLevelBase = NLB >> 8 = 0x40000
+nextLevelSize = NLS = 9
+
+// The upper nextLevelSize bits of the useful bits of vaddr
+// has the index into the Page Table Directory
+// Each entry is 8 bytes.
+shift = totalSize - nextLevelSize = 39 - 9 = 30
+mask = (1 << nextLevelSize) - 1  = 0xFF
+index = (vaddr >> shift) & mask = 0
+
+entry_addr = nextlevelBase + index * 8 = 0x40000 = RADIX_SECOND_LEVEL
+V = 1
+L = 1
+RPN = 0
+This is a leaf node.
+
+Second Level
+----------------
+
+// We no longer need the upper nextLevelSize useful bits
+// in the vaddr. Discard them. Call remaining bits of vaddr as useful
+// bits. These bits will tell us precisely which location in the
+// real page should we fetch the data from.
+totalSize = totalSize - nextLevelSize = 39 - 9 = 30
+
+//Compute the real page number base.
+rpn_addr = (RPN << 12) = 0
+mask = (1ULL << totalSize) - 1 = 0x000000001fffffff
+rpn_mask = ~mask               = 0xffffffffe0000000
+
+phys_addr = (rpn_addr & rpn_mask) | (vaddr & mask)
+          = (0 & 0xffffffffe0000000) | (0x1000 & 0x1fffffff)
+         = 0x1000
+
+
+Hence Virtual address = Physical Address.
+
+================== Example 2 : Hypervisor Kernel =======================
+Example 2:
+MSR[HV] = 1, MSR[PR] = 0
+vaddr = 0xc000010800003000
+
+PTCR : PATB = 0x10 = Partition Table Base (right shifted by 12)
+       PATS = 0x4  = Partition Table Size (add 12)
+
+Getting the Partition Table Entry (PATE0 and PATE1)
+
+Partition table base address is obtained by left-shifting
+PATB by 12 bits. Because the Partition table base is always aligned
+to 4k which is also the minimum size of the partition table.
+
+patb_addr = PATB << 12 = 0x10000
+
+effLPID = 0 // Hypervisor HV=1.
+
+pate1_offset = 0 * 16 + 8 = 8  // Partition Table second word is PATE1
+                               // for this effLPID
+
+pate1_addr = patb_addr + pate1_offset = 0x10008 = PARTITION_TABLE_2
+From PARTITION_TABLE_2
+PRTB = 0x1000
+prtb_addr = PRTB << 12 = 0x1000000
+
+effPID = SPRN_PIDR = 0 // HV=1,PR=0, Quadrant 0b11 = Hypervisor Kernel
+prte0_offset = effPID * 16 = 0 //First double word in Process Table
+                                // Indexed by effPID
+
+prte0_addr = prtb_addr + prte0_offset = 0x1000000 = PROCESS_TABLE_1
+
+------------------ The Walk Begins Now --------------------
+
+From PROCESS_TABLE_1
+RPDB  = 0x30
+RPDS  = 12
+RTS = RTS1 << 3 | RTS2 = 0x2 << 3 | 5 = 1 << 4 + 5 = 21
+totalSize = RTS + 31 = 21 + 31 = 52 = virtual address space used
+                                      by software
+
+Root Level
+----------------
+
+nextLevelBase = RPDB << 12 = 0x30000
+nextLevelSize = RPDS = 12
+
+// The lower totalSize bits of vaddr are the useful bits.
+// The upper nextLevelSize bits these useful bits
+// has the index into the Page Table Directory
+// Each entry is 8 bytes.
+shift = totalSize - nextLevelSize = 52 - 12 = 40
+mask = (1 << nextLeveSize) - 1 = 0x1FFF
+index = (vaddr >> shift ) & mask = (0xc000010800003000 >> 40) & 0xFFF
+                                 = (0b1100 0000 0000 0000 0000 0001) & 0xFFF
+                                = (0xc000001) & 0xFFF
+                                = 0x001
+
+entry_addr = nextLevelBase + index * 8
+           = 0x30000 + 1*8 = 0x30008
+           = RADIX_ROOT_KERNEL_PTE
+V = 1
+L = 0
+NLB = 0x400
+NLS = 5
+
+This a directory. Hence obtain NLB and NLS
+
+First Level
+----------------
+
+// We no longer need the upper nextLevelSize of the useful bits
+// in the vaddr. Discard them. Call remaining bits of vaddr as useful bits.
+totalSize = totalSize - nextLevelSize = 52 - 12 = 40
+
+//Recompute the new Page Directory Base and the Size
+nextLevelBase = NLB >> 8 = 0x40000
+nextLevelSize = NLS = 5
+
+
+// The upper nextLevelSize bits of the useful bits
+// has the index into the Page Table Directory
+// Each entry is 8 bytes.
+shift = totalSize - nextLevelSize = 40 - 5 = 35
+mask = (1 << nextLeveSize) - 1 = 0x1F
+index = (vaddr >> shift ) & mask = (0xc000010800003000 >> 35) & 0x1F
+                                 = (0b0001 1000 0000 0000 0000 0000 0010 0001) & 0x1F
+                                = (0x18000021) & 0x1F
+                                = 0x01
+
+entry_addr = nextLevelBase + index * 8
+           = 0x40000 + 1*8 = 0x40008
+           = RADIX_SECOND_LEVEL_KERNEL_PTE
+
+V = 1
+L = 0
+NLB = 0x500
+NLS = 5
+
+Again this is a directory. Hence using the NLB and NLS go to the next
+level
+
+Second Level
+----------------
+
+// We no longer need the upper nextLevelSize bits of the useful bits.
+//in the vaddr. Discard them. Call remaining bits of vaddr as useful bits.
+totalSize = totalSize - nextLevelSize = 40 - 5 = 35
+
+//Recompute the new Page Directory Base and the Size
+nextLevelBase = NLB >> 8 = 0x50000
+nextLevelSize = NLS = 5
+
+// The upper nextLevelSize bits of vaddr
+// has the index into the Page Table Directory
+// Each entry is 8 bytes.
+shift = totalSize - nextLevelSize = 35 - 5 = 30
+mask = (1 << nextLeveSize) - 1 = 0x1F
+
+index = (vaddr >> shift ) & mask = (0xc000010800003000 >> 30) & 0xF
+                                 = (0b0001 1000 0000 0000 0000 0000 0010 0001 0000) & 0xF
+                                = (0x18000210) & 0xF
+                                = 0x0
+
+entry_addr = nextLevelBase + index * 8
+           = 0x50000 + 0*8 = 0x50000
+           = RADIX_THIRD_LEVEL_KERNEL_PTE
+
+V=1
+L=1
+RPN=0
+
+This is the leaf level
+
+Third Level
+----------------
+
+// We no longer need the upper nextLevelSize useful bits.
+// in the vaddr. Discard them. Call remaining bits of vaddr as useful
+// bits. These bits will tell us precisely which location in the
+// real page should we fetch the data from.
+totalSize = totalSize - nextLevelSize = 35 - 5 = 30
+
+//Compute the real page number base.
+rpn_addr = (RPN << 12) = 0
+mask = (1ULL << totalSize) - 1 = 0x000000001fffffff
+rpn_mask = ~mask               = 0xffffffffe0000000
+
+phys_addr = (rpn_addr & rpn_mask) | (vaddr & mask)
+          = (0 & 0xffffffffe0000000) | (0xc000010800003000 & 0x1fffffff)
+         = 0x3000
+
+Hence Virtual address 0xc000010800003000 is mapped to Physical Address
+0x3000.
diff --git a/src/arch/power/radixwalk.cc b/src/arch/power/radixwalk.cc
new file mode 100644 (file)
index 0000000..0445796
--- /dev/null
@@ -0,0 +1,438 @@
+#include "arch/power/radixwalk.hh"
+
+#include <memory>
+
+#include "arch/power/miscregs.hh"
+#include "arch/power/tlb.hh"
+#include "base/bitfield.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "debug/RadixWalk.hh"
+#include "mem/packet_access.hh"
+#include "mem/request.hh"
+
+#define PRTB_SHIFT     12
+#define PRTB_MASK      0x0ffffffffffff
+#define PRTB_ALIGN     4
+#define TABLE_BASE_ALIGN     PRTB_SHIFT
+
+#define RPDB_SHIFT     8
+#define RPDB_MASK      0x0fffffffffffff
+
+#define RPDS_SHIFT     0
+#define RPDS_MASK      0x1f
+
+#define NLB_SHIFT      RPDB_SHIFT
+#define NLB_MASK       RPDB_MASK
+
+#define NLS_SHIFT      RPDS_SHIFT
+#define NLS_MASK       RPDS_MASK
+
+#define DIR_BASE_ALIGN  RPDB_SHIFT
+
+#define RTS1_SHIFT     61
+#define RTS1_MASK      0x3
+#define RTS2_BITS      3
+#define RTS2_SHIFT     5
+#define RTS2_MASK      ((1 << RTS2_BITS) - 1)
+
+#define RPN_MASK      0x01fffffffffff000
+
+#define QUADRANT_MASK 0xc000000000000000
+#define QUADRANT00   0x0000000000000000
+#define QUADRANT01   0x4000000000000000
+#define QUADRANT10   0x8000000000000000
+#define QUADRANT11   0xc000000000000000
+
+#define extract(x, shift, mask)   ((x >> shift) & mask)
+#define align(x, bits) (x << bits)
+
+#define getRTS(x)      ((extract(x, RTS1_SHIFT, RTS1_MASK) << RTS2_BITS) | \
+                        (extract(x, RTS2_SHIFT, RTS2_MASK)))
+
+namespace PowerISA {
+
+uint64_t
+RadixWalk::readPhysMem(uint64_t addr, uint64_t dataSize)
+{
+    uint64_t ret;
+    Request::Flags flags = Request::PHYSICAL;
+
+    RequestPtr request = new Request(addr, dataSize, flags, this->masterId);
+    Packet *read = new Packet(request, MemCmd::ReadReq);
+    read->allocate();
+    this->port.sendAtomic(read);
+    ret = read->get<uint64_t>();
+
+    delete read->req;
+
+    return ret;
+}
+
+uint32_t geteffLPID(ThreadContext *tc)
+{
+    Msr msr = tc->readIntReg(INTREG_MSR);
+
+    if (msr.hv)
+        return 0;
+
+    return tc->readIntReg(INTREG_LPIDR);
+}
+
+uint32_t geteffPID(ThreadContext *tc, Addr vaddr)
+{
+    Msr msr = tc->readIntReg(INTREG_MSR);
+    uint64_t quadrant = vaddr & QUADRANT_MASK;
+
+    if (msr.hv && !msr.pr) { //Hypervisor Kernel
+        switch(quadrant) {
+        case QUADRANT11:
+            return 0;
+        case QUADRANT10:
+            return 0;
+        default:
+            return tc->readIntReg(INTREG_PIDR);
+        }
+    }
+
+    //Hypervisor Userspace or Guest
+    switch(quadrant) {
+    case QUADRANT11:
+        return 0;
+    case QUADRANT00:
+       return tc->readIntReg(INTREG_PIDR);
+    default:
+       if (msr.hv)
+           panic("Errorenous hypervisor Userspace Quadrant : %lx\n", quadrant);
+       else
+           panic("Errorenous Guest Quadrant : %lx\n", quadrant);
+    }
+
+    return tc->readIntReg(INTREG_PIDR);
+}
+
+Fault
+RadixWalk::start(ThreadContext * tc, RequestPtr req, BaseTLB::Mode mode)
+{
+    Addr vaddr = req->getVaddr();
+    // prte0 ---> Process Table Entry
+    DPRINTF(RadixWalk,"Translating vaddr = 0x%lx\n", vaddr);
+    uint64_t prte0 = getRPDEntry(tc, vaddr);
+    // rpdb, rpds --->  Root Page Directory Base and Size
+    uint64_t rpdb = extract(prte0, RPDB_SHIFT, RPDB_MASK);
+    uint64_t rpds = extract(prte0, RPDS_SHIFT, RPDS_MASK);
+    // rts = Radix Tree Size - 31.
+    uint64_t rts = getRTS(prte0);
+
+    uint64_t nextLevelBase = align(rpdb, DIR_BASE_ALIGN);
+    uint64_t nextLevelSize = rpds;
+
+    // usefulBits ---> radix tree size + 31
+    // These are the useful lower bits of vaddr used for
+    // address translation.
+    uint64_t usefulBits = rts + 31; //Typically is 52.
+
+    DPRINTF(RadixWalk,"RPDB: 0x%lx\n RPDS: 0x%lx\n usefulBits: %ld\n\n"
+            ,rpdb,rpds,usefulBits);
+
+    //TODO:
+    //==========
+    // Fault should be generated as a return value of walkTree. Perhaps
+    // we can pass paddr as a pointer in which the physical address can
+    // be returned.
+    // As of now we assume that there are no faults.
+    Addr paddr = this->walkTree(vaddr, nextLevelBase,
+                                nextLevelSize, usefulBits);
+    req->setPaddr(paddr);
+    DPRINTF(RadixWalk,"Radix Translated %#x -> %#x\n",vaddr,paddr);
+    return NoFault;
+}
+
+uint64_t
+RadixWalk::getRPDEntry(ThreadContext * tc, Addr vaddr)
+{
+    Ptcr ptcr = tc->readIntReg(INTREG_PTCR);
+    uint32_t efflpid = geteffLPID(tc);
+
+    DPRINTF(RadixWalk,"PTCR:%lx\n",(uint64_t)ptcr);
+    DPRINTF(RadixWalk,"effLPID: %x\n",efflpid);
+
+    //Accessing 2nd double word of partition table (pate1)
+    //Ref: Power ISA Manual v3.0B, Book-III, section 5.7.6.1
+    //           PTCR Layout
+    // ====================================================
+    // -----------------------------------------------
+    // | /// |     PATB                | /// | PATS  |
+    // -----------------------------------------------
+    // 0     4                       51 52 58 59    63
+    // PATB[4:51] holds the base address of the Partition Table,
+    // right shifted by 12 bits.
+    // This is because the address of the Partition base is
+    // 4k aligned. Hence, the lower 12bits, which are always
+    // 0 are ommitted from the PTCR.
+    //
+    // Thus, The Partition Table Base is obtained by (PATB << 12)
+    //
+    // PATS represents the partition table size right-shifted by 12 bits.
+    // The minimal size of the partition table is 4k.
+    // Thus partition table size = (1 << PATS + 12).
+    //
+    //        Partition Table
+    //  ====================================================
+    //  0    PATE0            63  PATE1             127
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //  |                      |                      | <-- effLPID
+    //  |----------------------|----------------------|
+    //           .
+    //           .
+    //           .
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //
+    // The effective LPID  forms the index into the Partition Table.
+    //
+    // Each entry in the partition table contains 2 double words, PATE0, PATE1,
+    // corresponding to that partition.
+    //
+    // In case of Radix, The structure of PATE0 and PATE1 is as follows.
+    //
+    //     PATE0 Layout
+    // -----------------------------------------------
+    // |1|RTS1|/|     RPDB          | RTS2 |  RPDS   |
+    // -----------------------------------------------
+    //  0 1  2 3 4                55 56  58 59      63
+    //
+    // HR[0] : For Radix Page table, first bit should be 1.
+    // RTS1[1:2] : Gives one fragment of the Radix treesize
+    // RTS2[56:58] : Gives the second fragment of the Radix Tree size.
+    // RTS = (RTS1 << 3 + RTS2) + 31.
+    //
+    // RPDB[4:55] = Root Page Directory Base.
+    // RPDS = Logarithm of Root Page Directory Size right shifted by 3.
+    //        Thus, Root page directory size = 1 << (RPDS + 3).
+    //        Note: RPDS >= 5.
+    //
+    //   PATE1 Layout
+    // -----------------------------------------------
+    // |///|       PRTB             |  //  |  PRTS   |
+    // -----------------------------------------------
+    // 0  3 4                     51 52  58 59     63
+    //
+    // PRTB[4:51]   = Process Table Base. This is aligned to size.
+    // PRTS[59: 63] = Process Table Size right shifted by 12.
+    //                Minimal size of the process table is 4k.
+    //                Process Table Size = (1 << PRTS + 12).
+    //                Note: PRTS <= 24.
+    //
+    //                Computing the size aligned Process Table Base:
+    //                   table_base = (PRTB  & ~((1 << PRTS) - 1)) << 12
+    //                Thus, the lower 12+PRTS bits of table_base will
+    //                be zero.
+
+    uint64_t pate1Addr = align(ptcr.patb, TABLE_BASE_ALIGN) +
+                         (efflpid*sizeof(uint64_t)*2) + 8;
+    uint64_t dataSize = 8;
+    uint64_t pate1 = this->readPhysMem(pate1Addr, dataSize);
+    DPRINTF(RadixWalk,"2nd Double word of partition table entry: %lx\n",pate1);
+
+    uint64_t prtb = extract(pate1, PRTB_SHIFT, PRTB_MASK);
+    prtb = align(prtb, TABLE_BASE_ALIGN);
+
+    //Ref: Power ISA Manual v3.0B, Book-III, section 5.7.6.2
+    //
+    //        Process Table
+    // ==========================
+    //  0    PRTE0            63  PRTE1             127
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //  |                      |                      | <-- effPID
+    //  |----------------------|----------------------|
+    //           .
+    //           .
+    //           .
+    //  |----------------------|----------------------|
+    //  |                      |                      |
+    //  |----------------------|----------------------|
+    //
+    // The effective Process id (PID) forms the index into the Process Table.
+    //
+    // Each entry in the partition table contains 2 double words, PRTE0, PRTE1,
+    // corresponding to that process
+    //
+    // In case of Radix, The structure of PRTE0 and PRTE1 is as follows.
+    //
+    //     PRTE0 Layout
+    // -----------------------------------------------
+    // |/|RTS1|/|     RPDB          | RTS2 |  RPDS   |
+    // -----------------------------------------------
+    //  0 1  2 3 4                55 56  58 59      63
+    //
+    // RTS1[1:2] : Gives one fragment of the Radix treesize
+    // RTS2[56:58] : Gives the second fragment of the Radix Tree size.
+    // RTS = (RTS1 << 3 + RTS2) << 31,
+    //        since minimal Radix Tree size is 4G.
+    //
+    // RPDB = Root Page Directory Base.
+    // RPDS = Root Page Directory Size right shifted by 3.
+    //        Thus, Root page directory size = RPDS << 3.
+    //        Note: RPDS >= 5.
+    //
+    //   PRTE1 Layout
+    // -----------------------------------------------
+    // |                      ///                    |
+    // -----------------------------------------------
+    // 0                                            63
+    // All bits are reserved.
+
+    uint32_t effPID = geteffPID(tc, vaddr);
+    DPRINTF(RadixWalk,"effPID=%d\n", effPID);
+    uint64_t prte0Addr = prtb + effPID*sizeof(prtb)*2 ;
+    DPRINTF(RadixWalk,"Process table base: %lx\n",prtb);
+    uint64_t prte0 = this->readPhysMem(prte0Addr, dataSize);
+    //prte0 ---> Process Table Entry
+
+    DPRINTF(RadixWalk,"process table entry: %lx\n\n",prte0);
+    return prte0;
+}
+
+Addr
+RadixWalk::walkTree(Addr vaddr ,uint64_t curBase ,
+                    uint64_t curSize ,uint64_t usefulBits)
+{
+        uint64_t dataSize = 8;
+
+        if (curSize < 5) {
+            panic("vaddr = %lx, Radix RPDS = %lx,is less than 5\n",
+                  vaddr, curSize);
+        }
+        // vaddr                    64 Bit
+        // vaddr |-----------------------------------------------------|
+        //       | Unused    |  Used                                   |
+        //       |-----------|-----------------------------------------|
+        //       | 0000000   | usefulBits = X bits (typically 52)      |
+        //       |-----------|-----------------------------------------|
+        //       |           |<--Cursize---->|                         |
+        //       |           |    Index      |                         |
+        //       |           |    into Page  |                         |
+        //       |           |    Directory  |                         |
+        //       |-----------------------------------------------------|
+        //                        |                       |
+        //                        V                       |
+        // PDE  |---------------------------|             |
+        //      |V|L|//|  NLB       |///|NLS|             |
+        //      |---------------------------|             |
+        // PDE = Page Directory Entry                     |
+        // [0] = V = Valid Bit                            |
+        // [1] = L = Leaf bit. If 0, then                 |
+        // [4:55] = NLB = Next Level Base                 |
+        //                right shifted by 8              |
+        // [59:63] = NLS = Next Level Size                |
+        //            |    NLS >= 5                       |
+        //            |                                   V
+        //            |                     |--------------------------|
+        //            |                     |   usfulBits = X-Cursize  |
+        //            |                     |--------------------------|
+        //            |---------------------><--NLS-->|                |
+        //                                  | Index   |                |
+        //                                  | into    |                |
+        //                                  | PDE     |                |
+        //                                  |--------------------------|
+        //                                                    |
+        // If the next PDE obtained by                        |
+        // (NLB << 8 + 8 * index) is a                        |
+        // nonleaf, then repeat the above.                    |
+        //                                                    |
+        // If the next PDE is a leaf,                         |
+        // then Leaf PDE structure is as                      |
+        // follows                                            |
+        //                                                    |
+        //                                                    |
+        // Leaf PDE                                           |
+        // |------------------------------|           |----------------|
+        // |V|L|sw|//|RPN|sw|R|C|/|ATT|EAA|           | usefulBits     |
+        // |------------------------------|           |----------------|
+        // [0] = V = Valid Bit                                 |
+        // [1] = L = Leaf Bit = 1 if leaf                      |
+        //                      PDE                            |
+        // [2] = Sw = Sw bit 0.                                |
+        // [7:51] = RPN = Real Page Number,                    V
+        //          real_page = RPN << 12 ------------->  Logical OR
+        // [52:54] = Sw Bits 1:3                               |
+        // [55] = R = Reference                                |
+        // [56] = C = Change                                   V
+        // [58:59] = Att =                                Physical Address
+        //           0b00 = Normal Memory
+        //           0b01 = SAO
+        //           0b10 = Non Idenmpotent
+        //           0b11 = Tolerant I/O
+        // [60:63] = Encoded Access
+        //           Authority
+        //
+        uint64_t shift = usefulBits - curSize;
+        uint64_t mask = (1UL << curSize) - 1;
+        uint64_t index = extract(vaddr, shift, mask);
+
+        uint64_t entryAddr = curBase + (index * sizeof(uint64_t));
+        Rpde rpde = this->readPhysMem(entryAddr, dataSize);
+        DPRINTF(RadixWalk,"rpde:%lx\n",(uint64_t)rpde);
+        usefulBits = usefulBits - curSize;
+        //Ref: Power ISA Manual v3.0B, Book-III, section 5.7.10.2
+        if (rpde.leaf == 1)
+        {
+                uint64_t realpn = rpde & RPN_MASK;
+                uint64_t pageMask = (1UL << usefulBits) - 1;
+                Addr paddr = (realpn & ~pageMask) | (vaddr & pageMask);
+
+                //TODO: Check for permissions.
+                // We aren't doing that right now
+                // If there is a mismatch in the permissions,
+                // generate a fault.
+                DPRINTF(RadixWalk,"paddr:%lx\n",paddr);
+                return paddr;
+        }
+
+        uint64_t nextLevelBase = align(rpde.NLB, DIR_BASE_ALIGN);
+        uint64_t nextLevelSize = rpde.NLS;
+        DPRINTF(RadixWalk,"NLB: %lx\n",(uint64_t)nextLevelBase);
+        DPRINTF(RadixWalk,"NLS: %lx\n",(uint64_t)nextLevelSize);
+        DPRINTF(RadixWalk,"usefulBits: %lx",(uint64_t)usefulBits);
+        return walkTree(vaddr, nextLevelBase, nextLevelSize, usefulBits);
+}
+
+void
+RadixWalk::RadixPort::recvReqRetry()
+{
+
+}
+
+bool
+RadixWalk::RadixPort::recvTimingResp(PacketPtr pkt)
+{
+    return true;
+}
+
+BaseMasterPort &
+RadixWalk::getMasterPort(const std::string &if_name, PortID idx)
+{
+    if (if_name == "port")
+        return port;
+    else{
+        return MemObject::getMasterPort(if_name, idx);
+    }
+}
+
+/* end namespace PowerISA */ }
+
+PowerISA::RadixWalk *
+PowerRadixWalkParams::create()
+{
+    return new PowerISA::RadixWalk(this);
+}
diff --git a/src/arch/power/radixwalk.hh b/src/arch/power/radixwalk.hh
new file mode 100644 (file)
index 0000000..3a9efb9
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __ARCH_POWER_RADIX_WALK_HH__
+#define __ARCH_POWER_RADIX_WALK_HH__
+
+#include "arch/power/tlb.hh"
+#include "base/bitunion.hh"
+#include "base/types.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "params/PowerRadixWalk.hh"
+#include "sim/faults.hh"
+#include "sim/system.hh"
+
+class ThreadContext;
+
+namespace PowerISA
+{
+    class RadixWalk : public MemObject
+    {
+      protected:
+        // Port for accessing memory
+        class RadixPort : public MasterPort
+        {
+          public:
+            RadixPort(const std::string &_name, RadixWalk * _rwalk) :
+                  MasterPort(_name, _rwalk), rwalk(_rwalk)
+            {}
+
+          protected:
+            RadixWalk *rwalk;
+            bool recvTimingResp(PacketPtr pkt);
+            void recvReqRetry();
+        };
+
+        friend class RadixPort;
+        RadixPort port;
+        System * sys;
+        MasterID masterId;
+      uint64_t readPhysMem(uint64_t addr, uint64_t dataSize);
+
+      public:
+
+        BitUnion64(Rpde)
+                Bitfield<63> valid;
+                Bitfield<62> leaf;
+                Bitfield<59, 8>  NLB;
+                Bitfield<4, 0> NLS;
+        EndBitUnion(Rpde)
+
+        Fault start(ThreadContext * _tc, RequestPtr req, BaseTLB::Mode mode);
+        BaseMasterPort &getMasterPort(const std::string &if_name,
+                                      PortID idx = InvalidPortID);
+      Addr getRPDEntry(ThreadContext * tc, Addr vaddr);
+        Addr walkTree(Addr vaddr ,uint64_t ptbase ,
+                      uint64_t ptsize ,uint64_t psize);
+
+        typedef PowerRadixWalkParams Params;
+
+        const Params *
+        params() const
+        {
+            return static_cast<const Params *>(_params);
+        }
+
+        RadixWalk(const Params *params) :
+            MemObject(params), port(name() + ".port", this),
+            sys(params->system),
+            masterId(sys->getMasterId(this, name()))
+        {
+        }
+    };
+}
+#endif // __ARCH_POWER_RADIX_WALK_HH__
index 5162764ca6c1b0f1d8ccb22df3907de2d9f2d7dc..ae25e7d1c91a2a4c690dfe6d70431e5291a58654 100644 (file)
@@ -28,7 +28,6 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 #include "arch/power/tlb.hh"
 
 #include <string>
@@ -37,6 +36,7 @@
 #include "arch/power/faults.hh"
 #include "arch/power/miscregs.hh"
 #include "arch/power/pagetable.hh"
+#include "arch/power/radixwalk.hh"
 #include "arch/power/registers.hh"
 #include "arch/power/utility.hh"
 #include "base/inifile.hh"
@@ -53,6 +53,8 @@
 using namespace std;
 using namespace PowerISA;
 
+namespace PowerISA {
+
 ///////////////////////////////////////////////////////////////////////
 //
 //  POWER TLB
@@ -66,6 +68,8 @@ TLB::TLB(const Params *p)
     table = new PowerISA::PTE[size];
     memset(table, 0, sizeof(PowerISA::PTE[size]));
     smallPages = 0;
+
+    rwalk = p->walker;
 }
 
 TLB::~TLB()
@@ -217,6 +221,69 @@ TLB::unserialize(CheckpointIn &cp)
     }
 }
 
+RadixWalk *
+TLB::getWalker()
+{
+    return rwalk;
+}
+
+void
+TLB::regStats()
+{
+    BaseTLB::regStats();
+
+    read_hits
+        .name(name() + ".read_hits")
+        .desc("DTB read hits")
+        ;
+
+    read_misses
+        .name(name() + ".read_misses")
+        .desc("DTB read misses")
+        ;
+
+
+    read_accesses
+        .name(name() + ".read_accesses")
+        .desc("DTB read accesses")
+        ;
+
+    write_hits
+        .name(name() + ".write_hits")
+        .desc("DTB write hits")
+        ;
+
+    write_misses
+        .name(name() + ".write_misses")
+        .desc("DTB write misses")
+        ;
+
+
+    write_accesses
+        .name(name() + ".write_accesses")
+        .desc("DTB write accesses")
+        ;
+
+    hits
+        .name(name() + ".hits")
+        .desc("DTB hits")
+        ;
+
+    misses
+        .name(name() + ".misses")
+        .desc("DTB misses")
+        ;
+
+    accesses
+        .name(name() + ".accesses")
+        .desc("DTB accesses")
+        ;
+
+    hits = read_hits + write_hits;
+    misses = read_misses + write_misses;
+    accesses = read_accesses + write_accesses;
+}
+
 Fault
 TLB::translateInst(const RequestPtr &req, ThreadContext *tc)
 {
@@ -239,27 +306,36 @@ TLB::translateData(const RequestPtr &req, ThreadContext *tc, bool write)
 Fault
 TLB::translateAtomic(const RequestPtr &req, ThreadContext *tc, Mode mode)
 {
+    Addr paddr;
+    Addr vaddr = req->getVaddr();
+    DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
+    vaddr &= 0x0fffffffffffffff;
     if (FullSystem){
-       Msr msr = tc->readIntReg(MISCREG_MSR);
+       Msr msr = tc->readIntReg(INTREG_MSR);
         if (mode == Execute){
-            if (msr.ir)
-                fatal("Translate Atomic not Implemented for POWER");
+            if (msr.ir){
+                printf("MSR: %lx\n",(uint64_t)msr);
+                Fault fault = rwalk->start(tc,req, mode);
+                paddr = req->getPaddr();
+                return fault;
+            }
             else{
-                Addr vaddr = req->getVaddr();
                 DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
-                Addr paddr = vaddr;
+                paddr = vaddr;
                 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
                 req->setPaddr(paddr);
                 return NoFault;
             }
         }
         else{
-            if (msr.dr)
-                fatal("Translate Atomic not Implemented for POWER");
+            if (msr.dr){
+                Fault fault = rwalk->start(tc,req, mode);
+                paddr = req->getPaddr();
+                return fault;
+            }
             else{
-                Addr vaddr = req->getVaddr();
                 DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
-                Addr paddr = vaddr;
+                paddr = vaddr;
                 DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
                 req->setPaddr(paddr);
                 return NoFault;
@@ -308,6 +384,15 @@ TLB::index(bool advance)
     return *pte;
 }
 
+}
+
+BaseMasterPort *
+TLB::getMasterPort()
+{
+    return &rwalk->getMasterPort("port");
+}
+
+
 PowerISA::TLB *
 PowerTLBParams::create()
 {
index c119d93145967b19b2aeed1fac5287f14c4ceca2..293e01e26eeb71e9f9ddda9fc56653af930aeb6e 100644 (file)
@@ -90,6 +90,8 @@ struct TlbEntry
     }
 };
 
+class RadixWalk;
+
 class TLB : public BaseTLB
 {
   protected:
@@ -111,6 +113,8 @@ class TLB : public BaseTLB
     PowerISA::PTE *lookup(Addr vpn, uint8_t asn) const;
 
   public:
+    friend class RadixWalk;
+    RadixWalk *rwalk;
     typedef PowerTLBParams Params;
     TLB(const Params *p);
     virtual ~TLB();
@@ -132,6 +136,7 @@ class TLB : public BaseTLB
     void insert(Addr vaddr, PowerISA::PTE &pte);
     void insertAt(PowerISA::PTE &pte, unsigned Index, int _smallPages);
     void flushAll() override;
+    RadixWalk *getWalker();
 
     void
     demapPage(Addr vaddr, uint64_t asn) override
@@ -158,6 +163,9 @@ class TLB : public BaseTLB
     // Checkpointing
     void serialize(CheckpointOut &cp) const override;
     void unserialize(CheckpointIn &cp) override;
+
+    void regStats() override;
+    BaseMasterPort *getMasterPort() override;
 };
 
 } // namespace PowerISA
index ad91f3a5335198dad47737f0bc7ee2f6b11096f0..6e67ef792928755581116da0988a372d121fde1f 100644 (file)
@@ -179,7 +179,7 @@ class BaseCPU(ClockedObject):
     dcache_port = RequestPort("Data Port")
     _cached_ports = ['icache_port', 'dcache_port']
 
-    if buildEnv['TARGET_ISA'] in ['x86', 'arm', 'riscv']:
+    if buildEnv['TARGET_ISA'] in ['x86', 'arm', 'riscv', 'power']:
         _cached_ports += ["itb.walker.port", "dtb.walker.port"]
 
     _uncached_interrupt_response_ports = []