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

Nicolas Pitre nico at fluxnic.net
Fri Sep 4 11:51:42 EDT 2020


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 at 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
> 
> 



More information about the linux-arm-kernel mailing list