================ 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.