Nach dem Booten von Linux können Sie ein mit der Konsole verbundenes Gerät angeben, indem Sie es mit einer Option wie "console = ttyS0,115200" angeben.
Aber was ist, wenn ich das Protokoll sehen möchte, bevor es startet? Wie zeigen Sie es an? Lassen Sie uns das klären.
Die Umfragebasis ist hier.
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm
Obwohl es sich um eine Debugging-Routine handelt, die wirksam ist, wenn MM-Probleme oder printk nicht funktionieren, Es dient nur zum Debuggen und soll im Produktkern entfernt werden.
Sie müssen vorsichtig damit umgehen!
arch/arm/kernel/debug.S
/*
* Some debugging routines (useful if you've got MM problems and
* printk isn't working). For DEBUGGING ONLY!!! Do not leave
* references to these in a production kernel!
*/
Es scheint, dass Sie "Earlyprintk" als Boot-Option von Linux angeben sollten.
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/kernel-parameters.txt#n1135
Was passiert, wenn Sie dies angeben?
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/kernel/early_printk.c
Die Adresse des anzuzeigenden Zeichens wird an die Funktion printascii () übergeben.
Klicken Sie hier für die Definition von printascii. Im Fall von ARM Assembler ist das Argument in r0. In diesem Fall ist r0 ein Zeiger auf eine Zeichenfolge.
Ich denke.
arch/arm/kernel/debug.S
#ifndef CONFIG_DEBUG_SEMIHOSTING
ENTRY(printascii)
addruart_current r3, r1, r2 // 2.Erklärt in 1
1: teq r0, #0
ldrbne r1, [r0], #1
teqne r1, #0
reteq lr
2: teq r1, #'\n'
bne 3f
mov r1, #'\r'
waituart r2, r3 // 4.Erklärt in 2
senduart r1, r3 // 4.Erklärt in 3
busyuart r2, r3 // 4.Erklärt in 4
mov r1, #'\n'
3: waituart r2, r3
senduart r1, r3
busyuart r2, r3
b 1b
ENDPROC(printascii)
<Ausgelassen>
#else
ENTRY(printascii)
mov r1, r0
mov r0, #0x04 @ SYS_WRITE0
ARM( svc #0x123456 )
#ifdef CONFIG_CPU_V7M
THUMB( bkpt #0xab )
#else
THUMB( svc #0xab )
#endif
ret lr
ENDPROC(printascii)
Das Verhalten ändert sich abhängig davon, ob DEBUG_SEMIHOSTING aktiviert ist oder nicht.
Wenn es ungültig ist, wird versucht, Zeichen auszugeben, indem adduart_current / waituart / senduart vollständig verwendet wird. Dies wird eine produktspezifische Implementierung sein (siehe unten).
Was ist, wenn es gültig ist? 0x04 wird im r0-Register gesetzt, und das anzuzeigende Zeichen wird im r1-Register gesetzt, und 0x123456 wird im ARM-Modus SVCed. Dies ist eine Funktion, die unabhängig vom Modell verwendet werden kann und (wahrscheinlich) über einen Debugger wie JTAG angezeigt werden kann.
Ich werde adduart_current erklären, ein Prozess, der allen Modellen gemeinsam ist.
arch/arm/kernel/debug.S
#ifdef CONFIG_MMU
.macro addruart_current, rx, tmp1, tmp2
addruart \tmp1, \tmp2, \rx // 4.Erklärt in 1
mrc p15, 0, \rx, c1, c0
tst \rx, #1
moveq \rx, \tmp1
movne \rx, \tmp2
.endm
#else /* !CONFIG_MMU */
.macro addruart_current, rx, tmp1, tmp2
addruart \rx, \tmp1, \tmp2
.endm
#endif /* CONFIG_MMU */
rx [out] zugängliche Adresse von tmp1 / tmp2 temp1 [tmp]: Wird vorübergehend verwendet temp2 [tmp]: Wird vorübergehend verwendet
Wenn MMU aktiviert ist, schalten Sie PHYS / VIRT entsprechend dem Status der MMU um. Wenn MMU deaktiviert ist, verwenden Sie PHYS.
Mit anderen Worten wird dem ersten Register (r3) die entsprechende Adresse zur Steuerung des UART-Geräts zugewiesen.
Nun wollen wir sehen, wo jede in printascii aufgerufene Funktion definiert ist.
arch/arm/Kconfig.debug
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions (read help!)"
depends on DEBUG_KERNEL
help
Say Y here to include definitions of printascii, printch, printhex
in the kernel. This is helpful if you are debugging code that
executes before the console is initialized.
Note that selecting this option will limit the kernel to a single
UART definition, as specified below. Attempting to boot the kernel
image on a different platform *will not work*, so this option should
not be enabled for kernels that are intended to be portable.
choice
prompt "Kernel low-level debugging port"
depends on DEBUG_LL
config DEBUG_ALPINE_UART0
bool "Kernel low-level debugging messages via Alpine UART0"
depends on ARCH_ALPINE
select DEBUG_UART_8250
help
Say Y here if you want kernel low-level debugging support
on Alpine based platforms.
Diese Optionen sind für echte Kernel-Hacker gedacht, die sich die Hände schmutzig machen möchten
Wählen Sie Y, um printascii, printch und printhex im Kernel zu definieren. Dies ist nützlich, wenn Sie den Code debuggen möchten, der vor der Initialisierung der Konsole ausgeführt wird.
Beachten Sie, dass die Auswahl dieser Option den Kernel auf eine einzelne UART-Definition beschränkt, wie unten gezeigt. Aktivieren Sie diese Option nicht auf tragbaren Kerneln, da sie * nicht funktioniert *, wenn Sie versuchen, das Kernel-Image auf einer anderen Plattform zu starten.
Also, es ist wirklich solide hier, also ist es ein Fix, der es weniger portabel macht.
Wenn DEBUG_ALPINE_UART0 usw. in den obigen Einstellungen definiert ist, wird DEBUG_UART_8250 usw. angegeben und durch die Definition des einzuschließenden Assembler-Codes ersetzt.
arch/arm/Kconfig.debug
config DEBUG_LL_INCLUDE
string
default "debug/sa1100.S" if DEBUG_SA1100
default "debug/palmchip.S" if DEBUG_UART_8250_PALMCHIP
default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250
default "debug/at91.S" if DEBUG_AT91_UART
default "debug/asm9260.S" if DEBUG_ASM9260_UART
default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
default "debug/dc21285.S" if DEBUG_DC21285_PORT
default "debug/meson.S" if DEBUG_MESON_UARTAO
default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
default "debug/exynos.S" if DEBUG_EXYNOS_UART
default "debug/efm32.S" if DEBUG_LL_UART_EFM32
default "debug/icedcc.S" if DEBUG_ICEDCC
Infolgedessen wird CONFIG_DEBUG_LL_INCLUDE zur Zeichenfolge "debug / *. S", die # eingeschlossen ist.
arch/arm/kernel/debug.S
#if !defined(CONFIG_DEBUG_SEMIHOSTING)
#include CONFIG_DEBUG_LL_INCLUDE
#endif
Klicken Sie hier, um Definitionen wie CONFOG_DEBUG_UART_PHTS anzuzeigen, die in Kürze in 4.1 verwendet werden.
arch/arm/Kconfig.debug
config DEBUG_UART_PHYS
hex "Physical base address of debug UART"
default 0x01c20000 if DEBUG_DAVINCI_DMx_UART0
default 0x01c28000 if DEBUG_SUNXI_UART0
default 0x01c28400 if DEBUG_SUNXI_UART1
default 0x01d0c000 if DEBUG_DAVINCI_DA8XX_UART1
default 0x01d0d000 if DEBUG_DAVINCI_DA8XX_UART2
default 0x01f02800 if DEBUG_SUNXI_R_UART
default 0x02530c00 if DEBUG_KEYSTONE_UART0
default 0x02531000 if DEBUG_KEYSTONE_UART1
default 0x03010fe0 if ARCH_RPC
:
config DEBUG_UART_VIRT
hex "Virtual base address of debug UART"
default 0xc881f000 if DEBUG_RV1108_UART2
default 0xc8821000 if DEBUG_RV1108_UART1
default 0xc8912000 if DEBUG_RV1108_UART0
default 0xe0010fe0 if ARCH_RPC
default 0xf0000be0 if ARCH_EBSA110
default 0xf0010000 if DEBUG_ASM9260_UART
default 0xf0100000 if DEBUG_DIGICOLOR_UA0
default 0xf01fb000 if DEBUG_NOMADIK_UART
default 0xf0201000 if DEBUG_BCM2835 || DEBUG_BCM2836
default 0xf1000300 if DEBUG_BCM_5301X
default 0xf1000400 if DEBUG_BCM_HR2
default 0xf1002000 if DEBUG_MT8127_UART0
default 0xf1006000 if DEBUG_MT6589_UART0
default 0xf1009000 if DEBUG_MT8135_UART3
default 0xf1023000 if DEBUG_BCM_IPROC_UART3
default 0xf11f1000 if DEBUG_VERSATILE
default 0xf1600000 if DEBUG_INTEGRATOR
:
:
Der eigentliche Assembler-Code wird jeweils unter include / debug implementiert. Verwenden Sie hier den bcm-Code, der den kürzesten Quellcode zu haben scheint. Überprüfen Sie einfach die Definition der bereitgestellten Funktion. 4.1 adduart, rp,rv,tmp
/arch/arm/include/debug/bcm63xx.S
.macro addruart, rp, rv, tmp
ldr \rp, =CONFIG_DEBUG_UART_PHYS
ldr \rv, =CONFIG_DEBUG_UART_VIRT
.endm
rp [out] : CONFIG_DEBUG_UART_PHYS rv [out] : CONFIG_DEBUG_UART_VIRT tmp [out]: Daten an waituart / busyuart übergeben
Diese Funktion wird auch indirekt von der mmu-Steuerung aufgerufen. Vielleicht wird dies nicht verwendet, wenn die iomap-Tabelle definiert ist ...
arch/arm/mm/mmu.c
/*
* Ask the machine support to map in the statically mapped devices.
*/
if (mdesc->map_io)
mdesc->map_io();
else
debug_ll_io_init();
:
:
#ifdef CONFIG_DEBUG_LL
void __init debug_ll_io_init(void)
{
struct map_desc map;
debug_ll_addr(&map.pfn, &map.virtual);
if (!map.pfn || !map.virtual)
return;
map.pfn = __phys_to_pfn(map.pfn);
map.virtual &= PAGE_MASK;
map.length = PAGE_SIZE;
map.type = MT_DEVICE;
iotable_init(&map, 1);
}
#endif
arch/arm/kernel/debug.S
#ifdef CONFIG_MMU
ENTRY(debug_ll_addr)
addruart r2, r3, ip
str r2, [r0]
str r3, [r1]
ret lr
ENDPROC(debug_ll_addr)
#endif
4.2 waituart, rd,rx
/arch/arm/include/debug/bcm63xx.S
.macro waituart, rd, rx
1001: ldr \rd, [\rx, #UART_IR_REG]
tst \rd, #(1 << UART_IR_TXEMPTY)
beq 1001b
.endm
rd [tmp]: Wird vorübergehend verwendet rx [in]: UART-Geräteport
Lesen Sie den Speicher in OFFSET von UART_IR_REG des UART-Geräteports und wiederholen Sie die Schleife, bis er mit # (1 << UART_IR_TXEMPTY) übereinstimmt.
4.3 senduart, rd,rx
/arch/arm/include/debug/bcm63xx.S
.macro senduart, rd, rx
/* word access do not work */
strb \rd, [\rx, #UART_FIFO_REG]
.endm
rd [in]: Zeichenkette exportieren rx [in]: UART-Geräteport
4.4 busyuart, rd,rx
/arch/arm/include/debug/bcm63xx.S
.macro busyuart, rd, rx
1002: ldr \rd, [\rx, #UART_IR_REG]
tst \rd, #(1 << UART_IR_TXTRESH)
beq 1002b
.endm
rd [tmp]: Wird vorübergehend verwendet rx [in]: UART-Geräteport
Lesen Sie den Speicher in OFFSET von UART_IR_REG des UART-Geräteports und wiederholen Sie die Schleife, bis er mit # (1 << UART_IR_TXTRESH) übereinstimmt.
das ist alles.
Recommended Posts