[LINUX] Comment imprimer des caractères sur la console avant de démarrer dans ARM

Comment puis-je imprimer des caractères sur la console avant de démarrer?

Après le démarrage de Linux, vous pouvez spécifier un périphérique connecté à la console en le spécifiant avec une option telle que console = ttyS0,115200.

Mais que faire si je veux voir le journal avant qu'il ne démarre? Comment l'affichez-vous? Faisons le tri.

La base de sondage est ici.

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm

0. Introduction

Bien qu'il s'agisse d'une routine de débogage efficace lorsque le problème MM ou printk ne fonctionne pas, Il est uniquement destiné au débogage et est censé être supprimé dans le noyau du produit.

Vous devez être prudent lors de sa manipulation!

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!
 */

1. Spécifiez earlyprintk au démarrage.

Il semble que vous deviez spécifier ʻearly printk` comme option de démarrage de linux.

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/admin-guide/kernel-parameters.txt#n1135

Que se passe-t-il lorsque vous spécifiez cela?

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm/kernel/early_printk.c

L'adresse du caractère à afficher est transmise à la fonction printascii ().

2. Imprimer les caractères avec print ascii

Cliquez ici pour la définition de printascii. Dans le cas de l'assembleur ARM, l'argument est dans r0. Dans ce cas, r0 est un pointeur vers une chaîne.

Je pense.

arch/arm/kernel/debug.S



#ifndef CONFIG_DEBUG_SEMIHOSTING

ENTRY(printascii)
        addruart_current r3, r1, r2 // 2.Expliqué en 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.Expliqué en 2
        senduart r1, r3 // 4.Expliqué en 3
        busyuart r2, r3 // 4.Expliqué en 4
        mov r1, #'\n'
3:      waituart r2, r3
        senduart r1, r3
        busyuart r2, r3
        b   1b
ENDPROC(printascii)

<Omis>

#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)

Le comportement change selon que DEBUG_SEMIHOSTING est activé ou non.

S'il n'est pas valide, il essaie de générer des caractères en utilisant pleinement adduart_current / waituart / senduart. Ce sera une implémentation spécifique au produit (voir ci-dessous).

Et s'il est valide? 0x04 est défini dans le registre r0, et le caractère à afficher est défini dans le registre r1 et 0x123456 est SVC en mode ARM. C'est une fonction qui peut être utilisée quel que soit le modèle, et peut être visualisée (probablement) via un débogueur tel que JTAG.

2.1 Vérifiez adduart_current

J'expliquerai adduart_current, qui est un processus commun à tous les modèles.

arch/arm/kernel/debug.S


#ifdef CONFIG_MMU
        .macro  addruart_current, rx, tmp1, tmp2
        addruart    \tmp1, \tmp2, \rx // 4.Expliqué en 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] adresse accessible de tmp1 / tmp2 temp1 [tmp]: utilisé pour temporaire temp2 [tmp]: utilisé pour temporaire

Si MMU est activé, changez PHYS / VIRT en fonction de l'état de MMU, Si MMU est désactivé, utilisez PHYS.

En d'autres termes, l'adresse appropriée pour contrôler le dispositif UART est attribuée au premier registre (r3).

3. Décidez du modèle d'assembleur à lire avec printascii

Voyons maintenant où est définie chaque fonction appelée dans printascii.

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.

Ces options sont destinées aux vrais hackers du noyau qui veulent se salir les mains

Sélectionnez Y pour définir printascii, printch et printhex dans le noyau. Cela sera utile si vous souhaitez déboguer le code qui s'exécute avant l'initialisation de la console.

Notez que la sélection de cette option limite le noyau à une seule définition UART, comme illustré ci-dessous. N'activez pas cette option sur les noyaux portables car elle ne fonctionnera * pas * si vous essayez de démarrer l'image du noyau sur une autre plate-forme.

Donc, c'est vraiment solide ici, donc c'est un correctif qui le rend moins portable.

Si DEBUG_ALPINE_UART0 etc. est défini dans les paramètres ci-dessus, DEBUG_UART_8250 etc. est spécifié et remplacé par la définition du code assembleur à inclure.

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

À la suite de ce qui précède, CONFIG_DEBUG_LL_INCLUDE devient la chaîne de caractères " debug / *. S ", qui est #included.

arch/arm/kernel/debug.S



#if !defined(CONFIG_DEBUG_SEMIHOSTING)
#include CONFIG_DEBUG_LL_INCLUDE
#endif

Cliquez ici pour des définitions telles que CONFOG_DEBUG_UART_PHTS qui seront bientôt utilisées dans la version 4.1.

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

4. Assembleur réellement utilisé dans printascii

Le code assembleur réel est implémenté respectivement sous include / debug. Ici, en utilisant le code bcm, qui semble avoir le code source le plus court, Vérifiez facilement la définition de la fonction fournie. 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]: données transmises à waituart / busyuart

Cette fonction est également appelée indirectement depuis le contrôle mmu. Peut-être que cela ne sera pas utilisé si la table iomap est définie ...

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]: utilisé pour rx [in]: port de périphérique UART

Lisez la mémoire dans OFFSET de UART_IR_REG du port de périphérique UART et bouclez jusqu'à ce qu'elle corresponde à # (1 << UART_IR_TXEMPTY).

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]: Exporter la chaîne de caractères rx [in]: port de périphérique UART

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]: utilisé pour rx [in]: port de périphérique UART

Lisez la mémoire dans OFFSET de UART_IR_REG du port de périphérique UART et bouclez jusqu'à ce qu'elle corresponde à # (1 << UART_IR_TXTRESH).

Résumé

c'est tout.

Recommended Posts

Comment imprimer des caractères sur la console avant de démarrer dans ARM
Comment imprimer des messages de débogage sur la console Django
Comment écraser la sortie sur la console
Comment effacer les caractères générés par Python
Comment profiter de Python sur Android !! Programmation en déplacement !!
Comment utiliser le générateur
Comment imprimer des caractères sous forme de tableau avec la fonction d'impression de Python
Comment déployer Pybot, le manuel Python le plus simple, sur Heroku
Remarques sur l'utilisation de la guimauve dans la bibliothèque de schémas
Comment utiliser le décorateur
Comment augmenter l'axe
Comment démarrer la première projection
Remarque sur la façon de vérifier la connexion au port du serveur de licences
Est-il facile de synthétiser un médicament sur le marché?
Comment utiliser Jupyter sur le frontal de Spacon ITO
Une commande pour vérifier facilement la vitesse du réseau sur la console
Comment mettre à jour la version Python de Cloud Shell dans GCP
Comment calculer le coefficient d'autocorrélation
Comment utiliser la fonction zip
Comment utiliser Dataiku sous Windows
Remarques sur l'utilisation de pywinauto
Comment installer VMware-Tools sur Linux
Comment installer pycrypto sur Windows
Comment lire l'ensemble de données SNLI
Comment déployer django-compresseur sous Windows
Comment obtenir la version Python
Remarques sur l'utilisation des featuretools
Comment installer OpenCV sur Mac
Comment installer PyPy sur CentOS
Malentendu sur la façon de connecter CNN
Comment installer TensorFlow sur CentOS 7
Comment installer Maven sur CentOS
Comment utiliser le module ConfigParser
Remarques sur la rédaction de requirements.txt
Comment installer Music 21 sur Windows
Comment changer facilement l'environnement virtuel créé par Conda sur Jupyter
[Langage C] Comment utiliser la fonction crypt sous Linux [Hachage de mot de passe]
TLE semblait effrayant en fonction de la manière dont l'entrée était reçue
Comment enregistrer une seule donnée sur l'écran de gestion de Django
Comment rendre les caractères de Word Cloud monochromatiques
Comment afficher la barre de progression (tqdm)
Je veux sortir froidement sur la console
Comment installer aws-session-manager-plugin sur Manajro Linux
Comment lire pydoc sur l'interpréteur python
Comment installer drobertadams / toggl-cli sur Mac
Comment vérifier la version de Django
[Kivy] Comment installer Kivy sur Windows [Python]
Comment utiliser mecab, neologd-ipadic sur colab
Comment résoudre le problème d'emballage du bac
Comment régler l'heure du serveur sur l'heure japonaise
Comment créer Hello, World avec #Nix
Comment mettre à jour manuellement le cache AMP
[Linux] Comment utiliser la commande echo
Comment mettre à jour PHP sur Amazon Linux 2
Comment utiliser l'Assistant Google sur Windows 10
Comment effacer Python 2.x sur Mac.