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>
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 []
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):
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
cxx_class = 'PowerISA::TLB'
cxx_header = 'arch/power/tlb.hh'
size = Param.Int(64, "TLB size")
+ walker = Param.PowerRadixWalk(\
+ PowerRadixWalk(), "page table walker")
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')
SimObject('PowerInterrupts.py')
SimObject('PowerISA.py')
SimObject('PowerTLB.py')
+ SimObject('PowerSystem.py')
DebugFlag('Power')
+ DebugFlag('RadixWalk')
ISADesc('isa/main.isa')
}
}
- 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; }});
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.
--- /dev/null
+================ 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.
--- /dev/null
+#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);
+}
--- /dev/null
+#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__
* (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>
#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"
using namespace std;
using namespace PowerISA;
+namespace PowerISA {
+
///////////////////////////////////////////////////////////////////////
//
// POWER TLB
table = new PowerISA::PTE[size];
memset(table, 0, sizeof(PowerISA::PTE[size]));
smallPages = 0;
+
+ rwalk = p->walker;
}
TLB::~TLB()
}
}
+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)
{
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;
return *pte;
}
+}
+
+BaseMasterPort *
+TLB::getMasterPort()
+{
+ return &rwalk->getMasterPort("port");
+}
+
+
PowerISA::TLB *
PowerTLBParams::create()
{
}
};
+class RadixWalk;
+
class TLB : public BaseTLB
{
protected:
PowerISA::PTE *lookup(Addr vpn, uint8_t asn) const;
public:
+ friend class RadixWalk;
+ RadixWalk *rwalk;
typedef PowerTLBParams Params;
TLB(const Params *p);
virtual ~TLB();
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
// Checkpointing
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
+
+ void regStats() override;
+ BaseMasterPort *getMasterPort() override;
};
} // namespace PowerISA
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 = []