static int p2m_first_level_index(paddr_t addr) { /* * 1st pages are concatenated so zeroeth offset gives us the * index of the 1st page */ return zeroeth_table_offset(addr); }
/* Checking VA memory layout alignment. */ static inline void check_memory_layout_alignment_constraints(void) { /* 2MB aligned regions */ BUILD_BUG_ON(XEN_VIRT_START & ~SECOND_MASK); BUILD_BUG_ON(FIXMAP_ADDR(0) & ~SECOND_MASK); BUILD_BUG_ON(BOOT_RELOC_VIRT_START & ~SECOND_MASK); /* 1GB aligned regions */ #ifdef CONFIG_ARM_32 BUILD_BUG_ON(XENHEAP_VIRT_START & ~FIRST_MASK); #else BUILD_BUG_ON(DIRECTMAP_VIRT_START & ~FIRST_MASK); #endif /* Page table structure constraints */ #ifdef CONFIG_ARM_64 BUILD_BUG_ON(zeroeth_table_offset(XEN_VIRT_START)); #endif BUILD_BUG_ON(first_table_offset(XEN_VIRT_START)); BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= LPAE_ENTRIES); #ifdef CONFIG_DOMAIN_PAGE BUILD_BUG_ON(DOMHEAP_VIRT_START & ~FIRST_MASK); #endif }
void dump_pt_walk(paddr_t ttbr, paddr_t addr, unsigned int root_level, unsigned int nr_root_tables) { static const char *level_strs[4] = { "0TH", "1ST", "2ND", "3RD" }; const unsigned long root_pfn = paddr_to_pfn(ttbr); const unsigned int offsets[4] = { zeroeth_table_offset(addr), first_table_offset(addr), second_table_offset(addr), third_table_offset(addr) }; lpae_t pte, *mapping; unsigned int level, root_table; #ifdef CONFIG_ARM_32 BUG_ON(root_level < 1); #endif BUG_ON(root_level > 3); if ( nr_root_tables > 1 ) { /* * Concatenated root-level tables. The table number will be * the offset at the previous level. It is not possible to * concatenate a level-0 root. */ BUG_ON(root_level == 0); root_table = offsets[root_level - 1]; printk("Using concatenated root table %u\n", root_table); if ( root_table >= nr_root_tables ) { printk("Invalid root table offset\n"); return; } } else root_table = 0; mapping = map_domain_page(_mfn(root_pfn + root_table)); for ( level = root_level; ; level++ ) { if ( offsets[level] > LPAE_ENTRIES ) break; pte = mapping[offsets[level]]; printk("%s[0x%x] = 0x%"PRIpaddr"\n", level_strs[level], offsets[level], pte.bits); if ( level == 3 || !pte.walk.valid || !pte.walk.table ) break; /* For next iteration */ unmap_domain_page(mapping); mapping = map_domain_page(_mfn(pte.walk.base)); } unmap_domain_page(mapping); }
/* * Lookup the MFN corresponding to a domain's PFN. * * There are no processor functions to do a stage 2 only lookup therefore we * do a a software walk. */ static paddr_t __p2m_lookup(struct domain *d, paddr_t paddr, p2m_type_t *t) { struct p2m_domain *p2m = &d->arch.p2m; const unsigned int offsets[4] = { zeroeth_table_offset(paddr), first_table_offset(paddr), second_table_offset(paddr), third_table_offset(paddr) }; const paddr_t masks[4] = { ZEROETH_MASK, FIRST_MASK, SECOND_MASK, THIRD_MASK }; lpae_t pte, *map; paddr_t maddr = INVALID_PADDR; paddr_t mask = 0; p2m_type_t _t; unsigned int level, root_table; ASSERT(spin_is_locked(&p2m->lock)); BUILD_BUG_ON(THIRD_MASK != PAGE_MASK); /* Allow t to be NULL */ t = t ?: &_t; *t = p2m_invalid; if ( P2M_ROOT_PAGES > 1 ) { /* * Concatenated root-level tables. The table number will be * the offset at the previous level. It is not possible to * concatenate a level-0 root. */ ASSERT(P2M_ROOT_LEVEL > 0); root_table = offsets[P2M_ROOT_LEVEL - 1]; if ( root_table >= P2M_ROOT_PAGES ) goto err; } else root_table = 0; map = __map_domain_page(p2m->root + root_table); ASSERT(P2M_ROOT_LEVEL < 4); for ( level = P2M_ROOT_LEVEL ; level < 4 ; level++ ) { mask = masks[level]; pte = map[offsets[level]]; if ( level == 3 && !p2m_table(pte) ) /* Invalid, clobber the pte */ pte.bits = 0; if ( level == 3 || !p2m_table(pte) ) /* Done */ break; ASSERT(level < 3); /* Map for next level */ unmap_domain_page(map); map = map_domain_page(_mfn(pte.p2m.base)); } unmap_domain_page(map); if ( p2m_valid(pte) ) { ASSERT(mask); ASSERT(pte.p2m.type != p2m_invalid); maddr = (pte.bits & PADDR_MASK & mask) | (paddr & ~mask); *t = pte.p2m.type; } err: return maddr; }