diff mbox series

[3/3] RFC: ARM: head: Debug prints for section mappings

Message ID 20200904081949.5594-4-linus.walleij@linaro.org (mailing list archive)
State New, archived
Headers show
Series RFC: ARM section mapping debug prints | expand

Commit Message

Linus Walleij Sept. 4, 2020, 8:19 a.m. UTC
This creates a facility to print the early 1MB section mappings
of the kernel. By selecting the symbol CONFIG_DEBUG_EARLY_MAPPINGS
we can get a printout of some of the early mappings as they
are written into the swapper_pg_dir page table during very early
boot.

Currently I introduced hooks for printing the MMU enable 1:1
mappings, the kernel RAM mappings and the "r2" (ATAGs or DTB)
mappings.

The debug prints will show the physical address base and the
virtual address base map, something like this for example:

Uncompressing Linux... done, booting the kernel.
MMU enable: 0x40300000->0x40300000
Kernel RAM: 0x40000000->0xc0000000
Kernel RAM: 0x40100000->0xc0100000
Kernel RAM: 0x40200000->0xc0200000
(...)
Kernel RAM: 0x42500000->0xc2500000
Kernel RAM: 0x42600000->0xc2600000
ATAG/DTB  : 0x43000000->0xc3000000
ATAG/DTB  : 0x43100000->0xc3100000

This code does not try to be clever and shuffle registers
around like some puzzle, instead we just store out r1 thru r6
into memory while printing and read them back afterwards.
It is debug code anyway, so optimizations are not any concern
here.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/Kconfig.debug |  13 ++++-
 arch/arm/kernel/head.S | 109 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 120 insertions(+), 2 deletions(-)

Comments

Nicolas Pitre Sept. 4, 2020, 3:51 p.m. UTC | #1
On Fri, 4 Sep 2020, Linus Walleij wrote:

> This creates a facility to print the early 1MB section mappings
> of the kernel. By selecting the symbol CONFIG_DEBUG_EARLY_MAPPINGS
> we can get a printout of some of the early mappings as they
> are written into the swapper_pg_dir page table during very early
> boot.
> 
> Currently I introduced hooks for printing the MMU enable 1:1
> mappings, the kernel RAM mappings and the "r2" (ATAGs or DTB)
> mappings.
> 
> The debug prints will show the physical address base and the
> virtual address base map, something like this for example:
> 
> Uncompressing Linux... done, booting the kernel.
> MMU enable: 0x40300000->0x40300000
> Kernel RAM: 0x40000000->0xc0000000
> Kernel RAM: 0x40100000->0xc0100000
> Kernel RAM: 0x40200000->0xc0200000
> (...)
> Kernel RAM: 0x42500000->0xc2500000
> Kernel RAM: 0x42600000->0xc2600000
> ATAG/DTB  : 0x43000000->0xc3000000
> ATAG/DTB  : 0x43100000->0xc3100000
> 
> This code does not try to be clever and shuffle registers
> around like some puzzle, instead we just store out r1 thru r6
> into memory while printing and read them back afterwards.
> It is debug code anyway, so optimizations are not any concern
> here.
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
>  arch/arm/Kconfig.debug |  13 ++++-
>  arch/arm/kernel/head.S | 109 ++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 120 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
> index 87912e5c2256..a1620f2d0963 100644
> --- a/arch/arm/Kconfig.debug
> +++ b/arch/arm/Kconfig.debug
> @@ -1919,7 +1919,18 @@ config DEBUG_UNCOMPRESS
>  	  When this option is set, the selected DEBUG_LL output method
>  	  will be re-used for normal decompressor output on multiplatform
>  	  kernels.
> -	  
> +
> +config DEBUG_EARLY_MAPPINGS
> +	bool "Enable early section mapping debugging via DEBUG_LL output"
> +	depends on DEBUG_LL
> +	help
> +	  This option enables the kernel to print a list of all the 1 MB
> +	  section mappings used to map physical to virtual mempory
> +	  during the early boot. These mappings are used until the
> +	  kernel sets up the proper page table.
> +
> +	  The selected DEBUG_LL output method will be used for these debug
> +	  messages.
>  
>  config UNCOMPRESS_INCLUDE
>  	string
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 8b089c4c0d17..5758a99f6f0f 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -163,6 +163,109 @@ ENDPROC(stext)
>  	.long	PAGE_OFFSET
>  #endif
>  
> +#ifdef CONFIG_DEBUG_EARLY_MAPPINGS
> +__debug_tmp:
> +	.align
> +	.long	0, 0, 0, 0, 0, 0 /* r1 thru r6 */

You shouldn't write to the .text segment. This won't work for XIP as 
you'll read 0 back, or worse you'll trigger a flash memory controller 
operation. You should allocate your temporary buffer in the .bss section 
instead. Look at the printhex code for example.

> +__en_mmu_debug_txt:
> +	.asciz	"MMU enable: "
> +	.align
> +__ram_debug_txt:
> +	.asciz	"Kernel RAM: "
> +	.align
> +__r2_debug_txt:
> +	.asciz	"ATAG/DTB  : "
> +	.align

No need to align string starts. This is necessary only after the last 
one.

> +	/*
> +	 * This macro prints one physical to virtual section map using
> +	 * a section descriptor and a section table address
> +	 */
> +	.macro	dbg_pr, secd, vindex
> +	/* Only the physical address in secd please */
> +	bic	\secd, \secd, #0x000ff000
> +	bic	\secd, \secd, #0x00000ff0
> +	bic	\secd, \secd, #0x0000000f
> +	/* Convert the section index to a virtual address */
> +	bic	\vindex, \vindex, #0xff000000
> +	bic	\vindex, \vindex, #0x00ff0000
> +	bic	\vindex, \vindex, #0x0000c000
> +	lsr	\vindex, \vindex, #PMD_ORDER /* Convert to index */
> +	lsl	\vindex, \vindex, #SECTION_SHIFT /* Convert to virtual address */
> +	mov	r0, #'0'
> +	bl	printch
> +	mov	r0, #'x'
> +	bl	printch
> +	mov	r0, \secd
> +	bl	printhex8
> +	mov	r0, #'-'
> +	bl	printch
> +	mov	r0, #'>'
> +	bl	printch
> +	mov	r0, #'0'
> +	bl	printch
> +	mov	r0, #'x'
> +	bl	printch

Here I'd suggest you add the string "->0x", or even " -> 0x" for 
some breathing room, e.g.:

__num_prefix_debug_txt:
	.asciz	" -> 0x"

Then, with the first number you use:

	adr	r0, __num_prefix_debug_txt + 4
	bl	printascii

and no string offset for the second number.

> +	mov	r0, \vindex
> +	bl	printhex8
> +	mov	r0, #'\n'
> +	bl	printch
> +	.endm
> +
> +	/*
> +	 * r3 = current section descriptor, bits 31-20 is the physical address
> +	 * r5 = section table index
> +	 */
> +	.macro	dbg_pr_mmu
> +	adr	r0, __debug_tmp
> +	stmia	r0, {r1-r6}
> +	mov	r6, r3 /* Save r3 to r6 (print corrupts r3) */
> +	adr	r0, __en_mmu_debug_txt
> +	bl	printascii
> +	/* Print helper wants physical offset index */
> +	lsl	r5, r5, #PMD_ORDER
> +	dbg_pr	r6, r5
> +	adr	r0, __debug_tmp
> +	ldmia	r0, {r1-r6}
> +	.endm
> +
> +	/*
> +	 * r0 = section table index absolute address in physical memory
> +	 * r3 = current section descriptor, bits 31-20 is the physical address
> +	 */
> +	.macro	dbg_pr_ram
> +	mov	r5, r0 /* Save r0 in r5 */
> +	adr	r0, __debug_tmp
> +	stmia	r0, {r1-r6}
> +	mov	r6, r3 /* Save r3 to r6 (print corrupts r3) */

A long long time ago I had a patch that shuffled registers around so 
that the long lived values would be kept in r4 and above so to free 
r0-r3 for short lived values and parameter passing to make things easier 
when doing this sort of thing. I don't remember if I pushed it to the 
patch system, and if I did probably it got outdated and I didn't refresh 
it.

> +	adr	r0, __ram_debug_txt
> +	bl	printascii
> +	dbg_pr	r6, r5
> +	adr	r0, __debug_tmp
> +	ldmia	r0, {r1-r6}
> +	mov	r0, r5 /* Restore r0 from r5 */
> +	.endm
> +
> +	/* Debug text for "what is in r2" either ATAGs or a DTB */
> +	.macro	dbg_pr_r2
> +	adr	r0, __debug_tmp
> +	stmia	r0, {r1-r6}
> +	mov	r5, r3 /* Save r3 to r5 (print corrupts r3) */
> +	adr	r0, __r2_debug_txt
> +	bl	printascii
> +	dbg_pr	r6, r5
> +	adr	r0, __debug_tmp
> +	ldmia	r0, {r1-r6}
> +	.endm
> +#else
> +	/* Dummy stubs when not debugging */
> +	.macro	dbg_pr_mmu
> +	.endm
> +	.macro	dbg_pr_ram
> +	.endm
> +	.macro	dbg_pr_r2
> +	.endm
> +#endif /* CONFIG_DEBUG_EARLY_MAPPINGS */
> +
>  /*
>   * Setup the initial page tables.  We only setup the barest
>   * amount which are required to get the kernel running, which
> @@ -234,6 +337,7 @@ __create_page_tables:
>  	mov	r6, r6, lsr #SECTION_SHIFT
>  
>  1:	orr	r3, r7, r5, lsl #SECTION_SHIFT	@ flags + kernel base
> +	dbg_pr_mmu
>  	str	r3, [r4, r5, lsl #PMD_ORDER]	@ identity mapping
>  	cmp	r5, r6
>  	addlo	r5, r5, #1			@ next section
> @@ -246,7 +350,8 @@ __create_page_tables:
>  	ldr	r6, =(_end - 1)
>  	orr	r3, r8, r7
>  	add	r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
> -1:	str	r3, [r0], #1 << PMD_ORDER
> +1:	dbg_pr_ram
> +	str	r3, [r0], #1 << PMD_ORDER
>  	add	r3, r3, #1 << SECTION_SHIFT
>  	cmp	r0, r6
>  	bls	1b
> @@ -281,8 +386,10 @@ __create_page_tables:
>  	add	r3, r3, #PAGE_OFFSET
>  	add	r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
>  	orr	r6, r7, r0
> +	dbg_pr_r2
>  	str	r6, [r3], #1 << PMD_ORDER
>  	add	r6, r6, #1 << SECTION_SHIFT
> +	dbg_pr_r2
>  	str	r6, [r3]
>  1:
>  
> -- 
> 2.26.2
> 
>
Nicolas Pitre Sept. 4, 2020, 6:33 p.m. UTC | #2
On Fri, 4 Sep 2020, Nicolas Pitre wrote:

> On Fri, 4 Sep 2020, Linus Walleij wrote:
> 
> > +	.macro	dbg_pr_ram
> > +	mov	r5, r0 /* Save r0 in r5 */
> > +	adr	r0, __debug_tmp
> > +	stmia	r0, {r1-r6}
> > +	mov	r6, r3 /* Save r3 to r6 (print corrupts r3) */
> 
> A long long time ago I had a patch that shuffled registers around so 
> that the long lived values would be kept in r4 and above so to free 
> r0-r3 for short lived values and parameter passing to make things easier 
> when doing this sort of thing. I don't remember if I pushed it to the 
> patch system, and if I did probably it got outdated and I didn't refresh 
> it.

Found it. It is here: 

https://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=7234/2


Nicolas
diff mbox series

Patch

diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 87912e5c2256..a1620f2d0963 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -1919,7 +1919,18 @@  config DEBUG_UNCOMPRESS
 	  When this option is set, the selected DEBUG_LL output method
 	  will be re-used for normal decompressor output on multiplatform
 	  kernels.
-	  
+
+config DEBUG_EARLY_MAPPINGS
+	bool "Enable early section mapping debugging via DEBUG_LL output"
+	depends on DEBUG_LL
+	help
+	  This option enables the kernel to print a list of all the 1 MB
+	  section mappings used to map physical to virtual mempory
+	  during the early boot. These mappings are used until the
+	  kernel sets up the proper page table.
+
+	  The selected DEBUG_LL output method will be used for these debug
+	  messages.
 
 config UNCOMPRESS_INCLUDE
 	string
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 8b089c4c0d17..5758a99f6f0f 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -163,6 +163,109 @@  ENDPROC(stext)
 	.long	PAGE_OFFSET
 #endif
 
+#ifdef CONFIG_DEBUG_EARLY_MAPPINGS
+__debug_tmp:
+	.align
+	.long	0, 0, 0, 0, 0, 0 /* r1 thru r6 */
+__en_mmu_debug_txt:
+	.asciz	"MMU enable: "
+	.align
+__ram_debug_txt:
+	.asciz	"Kernel RAM: "
+	.align
+__r2_debug_txt:
+	.asciz	"ATAG/DTB  : "
+	.align
+	/*
+	 * This macro prints one physical to virtual section map using
+	 * a section descriptor and a section table address
+	 */
+	.macro	dbg_pr, secd, vindex
+	/* Only the physical address in secd please */
+	bic	\secd, \secd, #0x000ff000
+	bic	\secd, \secd, #0x00000ff0
+	bic	\secd, \secd, #0x0000000f
+	/* Convert the section index to a virtual address */
+	bic	\vindex, \vindex, #0xff000000
+	bic	\vindex, \vindex, #0x00ff0000
+	bic	\vindex, \vindex, #0x0000c000
+	lsr	\vindex, \vindex, #PMD_ORDER /* Convert to index */
+	lsl	\vindex, \vindex, #SECTION_SHIFT /* Convert to virtual address */
+	mov	r0, #'0'
+	bl	printch
+	mov	r0, #'x'
+	bl	printch
+	mov	r0, \secd
+	bl	printhex8
+	mov	r0, #'-'
+	bl	printch
+	mov	r0, #'>'
+	bl	printch
+	mov	r0, #'0'
+	bl	printch
+	mov	r0, #'x'
+	bl	printch
+	mov	r0, \vindex
+	bl	printhex8
+	mov	r0, #'\n'
+	bl	printch
+	.endm
+
+	/*
+	 * r3 = current section descriptor, bits 31-20 is the physical address
+	 * r5 = section table index
+	 */
+	.macro	dbg_pr_mmu
+	adr	r0, __debug_tmp
+	stmia	r0, {r1-r6}
+	mov	r6, r3 /* Save r3 to r6 (print corrupts r3) */
+	adr	r0, __en_mmu_debug_txt
+	bl	printascii
+	/* Print helper wants physical offset index */
+	lsl	r5, r5, #PMD_ORDER
+	dbg_pr	r6, r5
+	adr	r0, __debug_tmp
+	ldmia	r0, {r1-r6}
+	.endm
+
+	/*
+	 * r0 = section table index absolute address in physical memory
+	 * r3 = current section descriptor, bits 31-20 is the physical address
+	 */
+	.macro	dbg_pr_ram
+	mov	r5, r0 /* Save r0 in r5 */
+	adr	r0, __debug_tmp
+	stmia	r0, {r1-r6}
+	mov	r6, r3 /* Save r3 to r6 (print corrupts r3) */
+	adr	r0, __ram_debug_txt
+	bl	printascii
+	dbg_pr	r6, r5
+	adr	r0, __debug_tmp
+	ldmia	r0, {r1-r6}
+	mov	r0, r5 /* Restore r0 from r5 */
+	.endm
+
+	/* Debug text for "what is in r2" either ATAGs or a DTB */
+	.macro	dbg_pr_r2
+	adr	r0, __debug_tmp
+	stmia	r0, {r1-r6}
+	mov	r5, r3 /* Save r3 to r5 (print corrupts r3) */
+	adr	r0, __r2_debug_txt
+	bl	printascii
+	dbg_pr	r6, r5
+	adr	r0, __debug_tmp
+	ldmia	r0, {r1-r6}
+	.endm
+#else
+	/* Dummy stubs when not debugging */
+	.macro	dbg_pr_mmu
+	.endm
+	.macro	dbg_pr_ram
+	.endm
+	.macro	dbg_pr_r2
+	.endm
+#endif /* CONFIG_DEBUG_EARLY_MAPPINGS */
+
 /*
  * Setup the initial page tables.  We only setup the barest
  * amount which are required to get the kernel running, which
@@ -234,6 +337,7 @@  __create_page_tables:
 	mov	r6, r6, lsr #SECTION_SHIFT
 
 1:	orr	r3, r7, r5, lsl #SECTION_SHIFT	@ flags + kernel base
+	dbg_pr_mmu
 	str	r3, [r4, r5, lsl #PMD_ORDER]	@ identity mapping
 	cmp	r5, r6
 	addlo	r5, r5, #1			@ next section
@@ -246,7 +350,8 @@  __create_page_tables:
 	ldr	r6, =(_end - 1)
 	orr	r3, r8, r7
 	add	r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
-1:	str	r3, [r0], #1 << PMD_ORDER
+1:	dbg_pr_ram
+	str	r3, [r0], #1 << PMD_ORDER
 	add	r3, r3, #1 << SECTION_SHIFT
 	cmp	r0, r6
 	bls	1b
@@ -281,8 +386,10 @@  __create_page_tables:
 	add	r3, r3, #PAGE_OFFSET
 	add	r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
 	orr	r6, r7, r0
+	dbg_pr_r2
 	str	r6, [r3], #1 << PMD_ORDER
 	add	r6, r6, #1 << SECTION_SHIFT
+	dbg_pr_r2
 	str	r6, [r3]
 1: