Comme nous le savons, pour l'architecture X86 : Après avoir appuyé sur le bouton d'alimentation, la machine commence à exécuter du code à 0xFFFFFFF0, puis elle commence à exécuter du code dans le BIOS afin d'effectuer l'initialisation du matériel. Après l'exécution du BIOS, il utilise le bootloader pour charger l'image du système d'exploitation dans la mémoire. Enfin, le code du système d'exploitation commence à s'exécuter. Pour l'architecture ARM, quel est le processus de démarrage après avoir appuyé sur le bouton d'alimentation ? Merci !
Réponses
Trop de publicités?Actuellement, il existe deux modèles d'exception dans l'architecture ARM (la réinitialisation est considérée comme un type d'exception) :
Le modèle classique, utilisé dans les puces pré-Cortex et les puces Cortex-A/R actuelles. Dans celui-ci, la mémoire à 0 contient plusieurs gestionnaires d'exceptions :
Offset Handler
===============
00 Reset
04 Undefined Instruction
08 Supervisor Call (SVC)
0C Prefetch Abort
10 Data Abort
14 (Reserved)
18 Interrupt (IRQ)
1C Fast Interrupt (FIQ)
Lorsque l'exception se produit, le processeur commence l'exécution à partir d'un décalage spécifique, donc généralement cette table contient des branchements à instruction unique vers les gestionnaires complets plus loin dans le code. Une table vectorielle classique typique ressemble à ce qui suit :
00000000 LDR PC, =Reset
00000004 LDR PC, =Undef
00000008 LDR PC, =SVC
0000000C LDR PC, =PrefAbort
00000010 LDR PC, =DataAbort
00000014 NOP
00000018 LDR PC, =IRQ
0000001C LDR PC, =FIQ
Au moment de l'exécution, la table vectorielle peut être relocalisée à 0xFFFF0000, qui est souvent implémentée comme une plage de mémoire à couplage étroit pour le traitement le plus rapide des exceptions. Cependant, la réinitialisation à la mise sous tension commence généralement à 0x00000000 (mais dans certaines puces, elle peut être fixée à 0xFFFF0000 par une broche du processeur).
Le nouveau modèle de microcontrôleur est utilisé dans la gamme de puces Cortex-M. Là, la table de vecteurs à 0 est en fait une table de vecteurs (pointeurs), et non d'instructions. La première entrée contient la valeur de démarrage pour le registre SP, la seconde est le vecteur de réinitialisation. Cela permet d'écrire le gestionnaire de réinitialisation directement en C, puisque le processeur met en place la pile. Encore une fois, la table peut être déplacée au moment de l'exécution. La table de vecteurs typique pour Cortex-M commence comme ceci :
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
[...more vectors...]
Notez que dans les puces complexes modernes telles que l'OMAP3 ou l'A4 d'Apple, le premier morceau de code exécuté n'est généralement pas du code utilisateur mais la ROM de démarrage de la puce. Elle peut vérifier diverses conditions pour déterminer d'où charger le code utilisateur et s'il faut le charger tout court (par exemple, elle peut exiger une signature numérique valide). Dans ce cas, le code utilisateur peut devoir se conformer à différentes conventions de démarrage.
... A la fin, le code du système d'exploitation commence à s'exécuter. Pour l'architecture ARM, quel est le processus de démarrage après avoir appuyé sur le bouton d'alimentation ?
Cette réponse s'inscrit principalement dans le contexte des CPU Cortex-A modernes ; il existe une grande variété de plateformes ARM. Cependant, pour un ARM qui ressemble à un PC (tablette, téléphone portable, etc.) ...
Le CPU ARM va chercher une instruction à partir de 0x0 ou 0xffff0000 (pour un Cortex-M, il s'agit de données plutôt que d'une instruction). Les SOC ARM typiques ont une rom de démarrage qui utilise ce mécanisme. Pour un utilisateur final, vous devez consulter un manuel pour déterminer comment faire fonctionner votre code. En d'autres termes, il existe un BIOS intégré dans de nombreux SOC ARM qui utilisent le vecteur, mais vous devez utiliser quelque chose de différent pour que votre code s'exécute.
En général, le SOC ARM prend en charge plusieurs périphériques de démarrage. Le périphérique est déterminé par un FUSE (défini par un outil de fabrication) ou par des broches d'échantillonnage. Les broches seront des sorties du CPU dans un système en cours d'exécution, mais ont été tirées vers le haut/bas pour configurer un dispositif d'amorçage. Chaque dispositif d'amorçage aura des détails particuliers ; la ROM est simple, mais la flash NAND, la flash SPI, la MMC, etc. nécessitent des détails de configuration. Ceux-ci sont souvent fournis par un FUSE intégré et/ou des broches d'échantillonnage. Une petite partie du dispositif peut être lue pour configurer davantage le dispositif.
Dans le cas d'une puce ARM profondément intégrée, il se peut qu'elle ne s'amorce qu'à partir de la mémoire flash embarquée et que ce processus soit beaucoup plus simple ; mais je pense que, d'après le contexte de la question, vous faites référence à des CPU ARM plus avancés. Les systèmes ARM plus avancés ont un chargeur de démarrage. En effet, la quantité de code qu'un chargeur ROM peut charger est souvent limitée et/ou restreinte. Il est également souvent complexe de configurer la SDRAM et le chargeur de démarrage peut être structuré pour fonctionner à partir de la RAM statique interne, qui configure la SDRAM.
Voir : Pourquoi nous avons besoin d'un chargeur de démarrage
L'exécution du système d'exploitation a ses propres problèmes particuliers. Pour ARM Linux, c'était ATAGS et c'est maintenant devicetree. Les gens peuvent coder leur propre chargeur de démarrage ou utiliser l'un des nombreux projets open-source, u-boot étant le plus courant. U-boots supporte vxWorks, Linux, NetBSD, Plan9, OSE, QNX, Integrity, et OpenRTOS ainsi que les images binaires.
De nombreux périphériques Linux ARM originaux supportaient un démarrage direct de Linux sans chargeur de démarrage. Cependant, Linux ne prend pas en charge cette fonctionnalité dans la gamme principale, sauf pour quelques très vieux SOC/cores ARM.
Après la mise sous tension, le processeur commencera à exécuter un mode d'exception, le premier étant la réinitialisation. Comme la réinitialisation doit se faire en mode superviseur, puisque le processeur ne connaît pas l'état du registre à ce moment de l'exécution, il ne peut pas passer en mode superviseur. Pour cela, un petit code doit être écrit (voir à la fin). Après cela, d'autres exceptions peuvent être traitées en chargeant l'adresse dans le PC.
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
reset:
mrs r0,cpsr /* set the cpu to SVC32 mode */
bic r0,r0,#0x1f /* (superviser mode, M=10011) */
orr r0,r0,#0x13
msr cpsr,r0