From: Tom Rini Date: Tue, 25 Jun 2024 23:22:36 +0000 (-0600) Subject: Merge patch series "arm64: add a software pagetable walker" X-Git-Url: http://git.dujemihanovic.xyz/img/static/git-logo.png?a=commitdiff_plain;h=42276c3658173287078cf95461778c6e11631d34;p=u-boot.git Merge patch series "arm64: add a software pagetable walker" Caleb Connolly says: MMU issues are some of the most frustrating to debug. To make this slightly less unbearable, introduce a software pagetable walker for ARMv8. This can be called to dump a pagetable with the default formatter, or a custom callback can be provided to implement more complicated parsing. This can also be useful to dump the pagetable used by a previous bootloader stage (by reading out the ttbr register). Here is an example of the output when walking U-Boot's own memory map on a Qualcomm RB3 board: Walking pagetable at 000000017df90000, va_bits: 36. Using 3 levels [0x17df91000] | Table | | [0x17df92000] | Table | | [0x000001000 - 0x000200000] | Pages | Device-nGnRnE | Non-shareable [0x000200000 - 0x040000000] | Block | Device-nGnRnE | Non-shareable [0x040000000 - 0x080000000] | Block | Device-nGnRnE | Non-shareable [0x080000000 - 0x140000000] | Block | Normal | Inner-shareable [0x17df93000] | Table | | [0x140000000 - 0x17de00000] | Block | Normal | Inner-shareable [0x17df94000] | Table | | [0x17de00000 - 0x17dfa0000] | Pages | Normal | Inner-shareable --- 42276c3658173287078cf95461778c6e11631d34 diff --cc arch/arm/include/asm/armv8/mmu.h index ce655ce7a9,1348db4204..0ab681c893 --- a/arch/arm/include/asm/armv8/mmu.h +++ b/arch/arm/include/asm/armv8/mmu.h @@@ -129,6 -129,62 +129,62 @@@ static inline void set_ttbr_tcr_mair(in asm volatile("isb"); } + static inline void get_ttbr_tcr_mair(int el, u64 *table, u64 *tcr, u64 *attr) + { + if (el == 1) { + asm volatile("mrs %0, ttbr0_el1" : "=r" (*table)); + asm volatile("mrs %0, tcr_el1" : "=r" (*tcr)); + asm volatile("mrs %0, mair_el1" : "=r" (*attr)); + } else if (el == 2) { + asm volatile("mrs %0, ttbr0_el2" : "=r" (*table)); + asm volatile("mrs %0, tcr_el2" : "=r" (*tcr)); + asm volatile("mrs %0, mair_el2" : "=r" (*attr)); + } else if (el == 3) { + asm volatile("mrs %0, ttbr0_el3" : "=r" (*table)); + asm volatile("mrs %0, tcr_el3" : "=r" (*tcr)); + asm volatile("mrs %0, mair_el3" : "=r" (*attr)); + } else { + hang(); + } + } + + /** - * pte_walker_cb_t - callback function for walk_pagetable. ++ * typedef pte_walker_cb_t - callback function for walk_pagetable. + * + * This function is called when the walker finds a table entry + * or after parsing a block or pages. For a table the @end address + * is 0, and @addr is the address of the table. Otherwise, they + * are the start and end physical addresses of the block or page. + * + * @addr: PTE start address (PA), or address of table. Includes attributes. + * @end: End address of the region (or 0 for a table) + * @va_bits: Number of bits in the virtual address + * @level: Table level + * @priv: Private data for the callback + * + * Return: true to stop walking, false to continue + */ + typedef bool (*pte_walker_cb_t)(u64 addr, u64 end, int va_bits, int level, void *priv); + + /** + * walk_pagetable() - Walk the pagetable at ttbr and call @cb for each region + * + * @ttbr: Address of the pagetable to dump + * @tcr: TCR value to use + * @cb: Callback function to call for each entry + * @priv: Private data for the callback + */ + void walk_pagetable(u64 ttbr, u64 tcr, pte_walker_cb_t cb, void *priv); + + /** + * dump_pagetable() - Dump the pagetable at ttbr, printing each region and + * level. + * + * @ttbr: Address of the pagetable to dump + * @tcr: TCR value to use + */ + void dump_pagetable(u64 ttbr, u64 tcr); + struct mm_region { u64 virt; u64 phys;