Recently, I was debugging the Linux kernel and tracking the startup process. It is found that before turning on mmu, the physical address can be used to output debugging information by losing data to the serial port Fifo. However, once the code runs to enable mmu, in the assembly stage, mmu only maps the physical memory and does not map io, so it is unable to access the serial port.
At this time, the data output through the serial port is saved in the serial port buffer pool until the io mapping is established and the console is initialized in the c language stage.
However, if I want to track the kernel startup process in real time, what should I do?
At this time, we will mention the low level debug function of Linux.
This option is located at:
Kernel hacking ---> [*] Kernel debugging [*] Kernel low-level debugging functions
Opening this option will add config in. CONFIG_DEBUG_LL macro definition
It is preliminarily estimated that the following points will be affected:
(1) Of arch/arm/kernel/head.s__ create_page_tables section
(2) arch/arc/mach processor / macro definition part in processor. c
(3)kernel/prink.c
To provide DEBUG_LL function, we must also improve arch/arc/mach processor / include / Mach / debug macro. S
First, let's talk about the benefits. Why open the Kernel low-level debugging functions function.
After opening this macro definition, it will be displayed in the__ create_page_tables establishes some io mappings. The specific code is as follows:
#ifdef CONFIG_DEBUG_LL ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags /* * Map in IO space for serial debugging. * This allows debug messages to be output * via a serial console before paging_init. */ ldr r3, [r8, #MACHINFO_PGOFFIO] add r0, r4, r3 rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long) cmp r3, #0x0800 @ limit to 512MB movhi r3, #0x0800 add r6, r0, r3 ldr r3, [r8, #MACHINFO_PHYSIO] orr r3, r3, r7 1: str r3, [r0], #4 add r3, r3, #1 << 20 teq r0, r6 bne 1b
It is also mentioned in the code that the function of mapping io is to Click here Serial port debugging.
Where do the physical and virtual addresses used in this code come from? arch/arc/mach processor / macro definition part in processor. c
For example, the following processors:
MACHINE_START(EASIC0718, "SEP0718 board") .phys_io = 0x10005000, .io_pg_offst = ((0xe005000) >> 18) & 0xfffc, .boot_params = 0x30000100, .fixup = fixup_gfd0718, .map_io = sep0718_map_io, .init_irq = sep0718_init_irq, .init_machine = sep0718_init, .timer = &sep0718_timer, MACHINE_END
middle
.phys_io = 0x10005000,
.io_pg_offst = ((0xe005000) >> 18) & 0xfffc,
Is for__ create_ page_ Config for tables_ DEBUG_ Ll for io mapping
The last is the change to printk.c, which mainly defines void printscii (char *) for direct output.
After completing debug macro. S, you can use printscii. After the memory mapping is established, it can be used everywhere, whether in assembly or C, before or after mmu. The code will determine whether the mmu is turned on.
At the same time, print will keep a copy of data in the buffer pool and call printkasii to output directly. Therefore, the kernel will see the information output twice after startup.
Finally, paste debug-macro.S. note that the io address is related to the processor architecture and cannot be used directly.
/* linux/include/asm-arm/arch-sep0718/debug-macro.S * * Debugging macro include header * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #include .macro addruart,rx mrc p15, 0, \rx, c1, c0 tst \rx, #1 @ MMU enabled? moveq \rx, #0x10000000 movne \rx, #0xe0000000 add \rx, \rx, #0x5000 .endm .macro senduart,rd,rx str \rd, [\rx] @ UARTDR .endm .macro waituart,rd,rx 1001: ldr \rd, [\rx, #0x14] @ SYSFLGx tst \rd, #1 << 6 @ UBUSYx beq 1001b .endm .macro busyuart,rd,rx 1001: ldr \rd, [\rx, #0x14] @ SYSFLGx tst \rd, #1 << 6 @ UBUSYx beq 1001b .endm