16.3 Memóriatérkép és a bare-metal futási modell

16.3.1 Motiváció

Tételezzük fel, hogy egy kollégánk átad egy .bin firmware-t, és azt kérdezi: „Ez most miért nem indul el a QEMU-ban, amikor a main()-ben már csak egy LED-villogtatás van?” A hibakeresés kulcsa ilyenkor nem a C-forrásban, hanem a futási modell ismeretében van: hol keresi a processzor az első utasítást, honnan tölti be a veremmutatót, milyen címen éri el az első periféria-regisztert, és melyik címtartomány mit jelent egy linker script-ben. A Cortex-M világában ezek nem operációsrendszer-konfiguráció kérdései: rögzített, architektúra-szintű címek, amelyeket a linker script és a startup kód együtt „töltenek fel” tartalommal.

Ez az alfejezet a Cortex-M3-as futási modell alapját adja meg: megrajzoljuk a memóriatérképet, levezetjük a régiók méretét, majd nyomon követjük, mi történik közvetlenül a reset után, mielőtt bármilyen main() futna. Az AArch64 Linuxos világából érkező olvasó számára a legnagyobb váltás: nincs MMU, nincs virtuális cím, nincs _start libc-ről; a memória fizikai, fix, és a linker script dönti el, mi hova kerül.

16.3.2 Definíció: a Cortex-M3 fix memóriatérképe

Az Armv7-M architektúra (amelybe a Cortex-M3 tartozik) egy fix, 4 GB-os fizikai címtér-et definiál, nyolc darab 512 MB-os régióra osztva. Nem opcionális: ezek a címtartományok a specifikáció részei, és a mag viselkedése (pl. milyen bitet lehet gyorsítótárazni, milyen utasítás engedélyezett) ettől függ.

Régió Kezdőcím Végcím Méret Tipikus tartalom
Code 0x00000000 0x1FFFFFFF 512 MB Flash / ROM, vektorok, konstans adat
SRAM 0x20000000 0x3FFFFFFF 512 MB statikus változók, .data, .bss, verem, halom
Peripheral 0x40000000 0x5FFFFFFF 512 MB memory-mapped I/O (UART, GPIO, timer)
External RAM 0x60000000 0x9FFFFFFF 1 GB külső memória (opcionális)
External device 0xA0000000 0xDFFFFFFF 1 GB külső periféria (opcionális)
System: Private Peripheral Bus (PPB) 0xE0000000 0xE00FFFFF 1 MB SCS (SCB, SysTick, NVIC, MPU), ITM, DWT, FPB
System: vendor system 0xE0100000 0xFFFFFFFF 511 MB gyártóspecifikus

A sorok hézag és átfedés nélkül fedik a teljes 4 GB-ot: minden kezdőcím az előző sor végcíme + 1, az utolsó végcím 0xFFFFFFFF, és a méret mindig végcím − kezdőcím + 1. A két külső tartomány egyenként 1 GB, vagyis két-két 512 MB-os egység; a 0xE0000000-tól kezdődő utolsó 512 MB-os egységet (System) az architektúra tovább bontja PPB-re és gyártói részre.

A táblázat fogalmi jelentése: a 32 bites cím felső 3 bitje dönti el, melyik 512 MB-os egységbe esik (a két 1 GB-os külső tartomány két-két egységből áll, a 0xE0000000-s System egységet pedig az architektúra tovább bontja). A régiók méretét a mag nem korlátozza — egy adott chipen belül csak egy töredékük van „kitöltve” memóriával; a lyukakra írás BusFault-ot vált ki (azaz a mag fault kivételt dob, nem csendben eldobja az írást).

Definíció (memóriatérkép). A memory map az a hivatalos hozzárendelés, amely a 32 bites címtér szeleteit funkciókhoz (kód, RAM, periféria, mag-belső regiszterek) rendeli, és amelyet a mag és a linker script egyaránt ismer.

Definíció (bare-metal futási modell). Bare-metal (csupasz fém) futás alatt azt értjük, hogy a mag közvetlenül a reset-vektorról indul, nincs operációs rendszer, nincs dinamikus betöltő, minden címet (kód, verem, periféria) a fejlesztő által adott linker script és startup kód rendez el.

16.3.3 A régiók méretének levezetése

A 32 bites címtér 2322^{32} bájt = 4 GB. Ha nyolc egyenlő részre osztjuk:

23223=229 bájt=512 MB. \frac{2^{32}}{2^3} = 2^{29} \text{ bájt} = 512 \text{ MB}.

Ezért a régiók felső 3 bit alapján szelektálhatók. Az Address bitjei A[31:29] a régióindex; az alsó 29 bit a régión belüli eltolás. Például:

A cím értelmezése tehát két külön lépés: előbb a régió azonosítása, aztán a régión belüli dekódolás.

  1. Régióazonosítás. A[31:29] kiválasztja az 512 MB-os egységet. A System egységen belül A[31:20] = 0xE00 jelöli az 1 MB-os PPB-t (0xE0000000–0xE00FFFFF), minden más (0xE0100000–0xFFFFFFFF) gyártói terület.
  2. Dekódolás a PPB-n belül. A PPB minden címe ugyanazt a magas mintát hordozza (A[31:20] = 0xE00), ezért ezek a bitek az egyes eszközöket nem különítik el. Az eszközt az alacsonyabb bitek választják ki: A[19:12] a 4 KiB-os blokkot (például 0x0E a System Control Space, SCS: 0xE000E000–0xE000EFFF), azon belül A[11:0] a regisztert.

Kidolgozott dekódolás: 0xE000E100.

Lépés Bitek Érték Jelentés
régió A[31:29] 0b111 System egység
PPB-e? A[31:20] 0xE00 igen, PPB
blokk a PPB-n belül A[19:12] 0x0E SCS (0xE000E000–0xE000EFFF)
regiszter az SCS-ben A[11:0] 0x100 NVIC ISER0 (az NVIC 0xE000E100-tól kezdődik)

Ugyanígy 0xE000E010 az SCS-en belül a 0x010 eltolás, a SysTick vezérlőregisztere (SYST_CSR, a SysTick blokk 0xE000E010–0xE000E01F). A 0xE000E010 és a 0xE000E100 tehát A[31:12]-ben megegyezik, és csak az SCS-en belüli eltolásban különbözik.

16.3.4 Mit tartalmaz az egyes régió?

Code régió (0x00000000–). Ezen a címen található a vektortábla első szava (kezdeti SP), majd a második szava (reset-vektor), utána a többi kivétel belépési címe. Ezt követi a tényleges programkód (.text) és a konstans inicializált adatok (.rodata). Fizikailag ez lehet beágyazott Flash, vagy — QEMU-ban — egyszerű RAM, amit „ROM-ként” használunk. Fontos: a vektortáblának a régió kezdetén kell lennie (alapértelmezésben 0x00000000), mert a mag reset után ezt a címet használja; később a VTOR (Vector Table Offset Register) átírásával elmozdítható, ezzel a következő alfejezetekben még foglalkozunk.

SRAM régió (0x20000000–). Itt él a statikus adat (.data), a nulla-kezdőértékű (.bss), a verem (stack) és a halom (heap). A verem a legmagasabb címről lefelé nő (a PUSH a SP-t csökkenti ARM-en). A .data szakasz tartalma a Flash-ből másolódik át a startup kódban (lásd [a066](a066.html)), mert a Flash nem írható futás közben.

Periféria régió (0x40000000–). Itt helyezkednek el a Memory-mapped I/O regiszterek. A mag ugyanazokkal a LDR/STR utasításokkal éri el őket, mint a RAM-ot; a különbség az, hogy az írás/olvasás itt hardveres mellékhatást vált ki (UART-ba küld, GPIO-t billent, időzítőt indít). A pontos címek és bitmezők gyártó- és táblaspecifikusak; a részletes kezelés a [ach17](index.html#ach17) fejezetben következik. Most csak annyi a fontos: a 0x40000000-s régióban nem szabad „véletlen” programadatot elhelyezni.

PPB (0xE0000000–0xE00FFFFF). A mag belső perifériái: NVIC, SysTick, SCB, MPU, hibaregiszterek. Ide írva konfiguráljuk a megszakításokat ([ach16](index.html#ach16)) és a rendszerszintű viselkedést.

16.3.5 A reset mechanizmusa

Amikor a mag feszültség alá kerül (vagy a qemu-system-arm elindul), a hardver a reset-szekvenciát hajtja végre. A Reset a vektortáblában az 1-es vektorszámot kapja (a második szó), de a reset nem szokásos kivételbelépés: nincs veremre mentett keret, nincs EXC_RETURN, és a mag nem Handler módba lép. A szekvencia az architektúrában rögzített, operációs rendszertől függetlenül:

  1. SP betöltése. A mag beolvassa a 0x00000000 címen lévő 32 bites szót, és beírja a fő veremmutatóba (MSP, az R13 reset utáni nézete). Ez a kezdeti veremmutató, tipikusan az SRAM legfelső címe.
  2. PC és T-bit a reset-vektorból. A 0x00000004 címen lévő szó a reset-vektor. A bit0-ja nem a cím része: az EPSR.T bitbe kerül, és 1-nek kell lennie, mert a Cortex-M csak Thumb állapotot ismer. A PC-be a bit0 nélküli érték kerül, ez a reset-handler első utasításának (páros) címe. A vektor tehát például 0x00000041, a végrehajtás pedig a 0x00000040-en kezdődik. Ha a vektor bit0-ja 0, az első utasítás INVSTATE UsageFaultot okoz, ami HardFaulttá eszkalálódik.
  3. LR beállítása. LR (R14) 0xFFFFFFFF-re áll; ez azt jelzi, hogy nincs visszatérési cím (a BX LR itt fault-ot okoz, ami néha hasznos a „nem szabadna ide visszatérni” jelzésre).
  4. Mód és IPSR. A mag privilegizált Thread módban indul a fő veremmel (CONTROL.nPRIV = 0, CONTROL.SPSEL = 0), és az IPSR (Interrupt Program Status Register) értéke 0. Az IPSR az aktív kivétel számát mutatja Handler módban, Thread módban pedig 0-t. A „vektorszám 1” és az „aktív kivételszám 0” tehát nem ellentmondás: a reset-handler Thread módban fut, nem egy aktív Reset-kivétel kezelőjeként.

Ezek után a CPU már a saját reset-handlerünk első utasításánál tart, a main() fogalmilag még nem létezik — a reset-handler az, ami majd meghívja.

A mechanizmus kulcsa: a mag nem tudja, hogy az [SP] és [PC] érték honnan „származik”; csak azt tudja, hogy a 0-s címen lévő szavak tartalmát tölti be. Ezért a linkelési folyamatnak gondoskodnia kell arról, hogy a .vectors szekció pontosan a 0-s címre kerüljön, benne a helyes kezdeti SP-vel és reset-vektorral.

A reset utáni állapot a reset-handler első utasítása előtt GDB-vel ellenőrizhető. A -S kapcsolóval indított QEMU a resetet már elvégezte, de még egyetlen utasítást sem hajtott végre:

qemu-system-arm -machine mps2-an385 -cpu cortex-m3 -kernel lab-a063.elf \
    -S -gdb tcp::3333 -nographic          # egyik terminál
gdb-multiarch lab-a063.elf -ex "target remote :3333"   # másik terminál
(gdb) x/2xw 0                 # vektor[0] = kezdeti SP, vektor[1] = reset-vektor (bit0 = 1)
(gdb) p/x $sp                 # = vektor[0]
(gdb) p/x $pc                 # = vektor[1] & ~1 (páros cím), a Reset_Handler első utasítása
(gdb) p/x $xpsr & 0x1ff       # IPSR = 0: Thread mód
(gdb) p/x ($xpsr >> 24) & 1   # EPSR.T = 1
(gdb) p/x $lr                 # 0xffffffff
(gdb) p/x $control            # 0: privilegizált, MSP (ha a QEMU/GDB kiteszi ezt a regisztert)

Az ellenőrzés lényege a vektor és a végrehajtási cím különbsége: a x/2xw 0 második szava páratlan, a $pc ugyanez bit0 nélkül.

16.3.6 A QEMU mps2-an385 memóriatérképe

A könyv II. részének QEMU-baseline-ja az ARM MPS2+ AN385 tábla, Cortex-M3 maggal. A dokumentáció szerinti fő tartományok (a pontos címeket és bitmezőket a QEMU hivatalos machine-definíciója és a CMSDK periféria-dokumentáció alapján ellenőrizni szükséges a generálás időpontjában; az alábbi értékek a QEMU hw/arm/mps2.c forrásában és a hivatalos MPS2+ dokumentációban szereplő baseline-t tükrözik):

Címtartomány Méret Szerep
0x00000000–0x003FFFFF 4 MiB ZBT SSRAM1 — Code (vektortábla, kód, .rodata); a linker scriptben FLASH néven
0x20000000–0x203FFFFF 4 MiB ZBT SSRAM 2 & 3 együtt — SRAM (.data, .bss, stack); ez az egyetlen kanonikus RAM-tartomány
0x20400000–0x207FFFFF (4 MiB) az előző sor tükre (alias): ugyanaz a fizikai tár, nem második blokk
0x40000000– — CMSDK APB periféria-sáv kezdete (UART, timer, dual-timer, FPGAIO, SCC, GPIO)
0xE0000000–0xE00FFFFF 1 MiB PPB: SCS (SCB, SysTick, NVIC)

A QEMU 8.2.2 hw/arm/mps2.c forrása szerint az AN385-ön a 0x20000000–0x203fffff tartomány az SSRAM 2 és 3 együttese, a 0x20400000–0x207fffff pedig ennek tükre. Aki a tükröt külön tárolóként számolja (például oda teszi a vermet, a .data-t pedig az alsó tartományba), a program saját adatait írja felül egy másik címen keresztül: a 0x20400000 + x és a 0x20000000 + x ugyanaz a bájt. A könyv linker scriptjei ezért csak a 0x20000000-tól induló 4 MiB-ot használják.

A linker scriptek FLASH nevű régiója itt egy betöltött SRAM-ra adott név, nem fizikai flash-tulajdonság: a QEMU az ELF-et ide tölti, és a tartalom futás közben akár írható is. A név a valódi mikrokontrollerek szokását követi, ahol ugyanez a szerep valódi flashre esik; a „flash nem írható” jellegű állítások a QEMU-gépre nem érvényesek.

A konkrét 0x40000000-ás periféria-offsetek (melyik UART hol van, hol a timer) a [ach17](index.html#ach17) fejezetben és a XVII. fejezet laborjaiban lesznek tételesen bevezetve. Itt csak annyit szögezzünk le: amit a linker script MEMORY blokkja megad, annak egyeznie kell a QEMU machine tényleges térképével — különben a firmware betöltődik ugyan, de a Python __main vagy a verem az első PUSH-nál BusFault-ot okoz.

Megjegyzés. A fenti 4 MiB-os ZBT SSRAM értékek a szimulált QEMU-memóriamodellek méretei. A fizikai MPS2+ táblán a tényleges SSRAM ennél nagyobb is lehet; natív hardveren a linker script által kijelölt régiók a tábla CMSIS-fájljából (device header) származnak, nem a QEMU-ból.

16.3.7 Kidolgozott példa: minimális vektortábla és SP

Munkakönyvtár: ~/arm-labor/cm/a063/ — az alfejezet minden laborfájlja ide kerül, és minden parancs innen futtatandó (a könyvtárrendet a Labor-alapkörnyezet alfejezet írja le).

mkdir -p ~/arm-labor/cm/a063
cd ~/arm-labor/cm/a063

Az alábbi GNU assembler forrás egy minimális, de teljes vektortáblát mutat, amely pontosan azt kódolja, amiről az előbb szó volt. A feltételezett címtér: 4 MB Code 0x00000000-tól, 4 MB SRAM 0x20000000-tól.

/* lab-a063-vectors.s: minimális vektortábla Cortex-M3-hoz */
    .syntax unified
    .cpu cortex-m3
    .thumb

    .section .vectors, "a", %progbits
    .word   0x20010000          /* [0x00] kezdeti SP: a verem teteje az SRAM-ban */
    .word   Reset_Handler       /* [0x04] reset-vektor (a .thumb_func miatt bit0 = 1) */
    /* [0x08] NMI, [0x0C] HardFault, ... itt kihagyva a rövidség kedvéért */

    .section .text
    .thumb_func
    .global Reset_Handler
Reset_Handler:
    /* Itt még nincs C-runtime. Legalább egy végtelen ciklus kell. */
    ldr     r0, =0x20000000
1:  b       1b                  /* végtelen ciklus, önmagára ugrik */

A hozzá tartozó linker script-részlet a MEMORY régiókat a fenti térképhez köti:

/* lab-a063.ld: memóriatérkép MPS2-AN385-höz */
MEMORY
{
    FLASH (rx)  : ORIGIN = 0x00000000, LENGTH = 4M
    SRAM  (rwx) : ORIGIN = 0x20000000, LENGTH = 4M
}

SECTIONS
{
    .vectors : { KEEP(*(.vectors)) } > FLASH
    .text         : { *(.text*) }              > FLASH
}

A vektortábla és a reset-handler itt a II. rész kanonikus neveit használja (.vectors, Reset_Handler); a teljes, közös startup/linker párt a Linker script alapjai és a Startup kód alfejezet adja.

Várható regiszterállapot a Reset_Handler első utasítása előtt (levezetett, a fenti GDB-lépésekkel ellenőrizendő):

Regiszter Érték Miért
SP (R13, MSP) 0x20010000 a [0x00000000] szó betöltve
[0x00000004] (reset-vektor) Reset_Handler címe, bit0 = 1 a .thumb_func miatt páratlan
PC (R15) a reset-vektor bit0 nélkül (páros) a végrehajtás címe
LR (R14) 0xFFFFFFFF reset szekvencia
EPSR.T 1 a reset-vektor bit0-jából
IPSR 0 Thread mód, nincs aktív kivétel
CONTROL 0 privilegizált, MSP

A futtatás QEMU-ban (qemu-system-arm) tipikusan úgy indul, hogy a -kernel opcióként átadott ELF-ből a QEMU kiolvassa a belépési pontot, és a 0-s címen elhelyezi a tartalmat. A várt viselkedés illusztratív: tényleges regiszterértékek helyes ellenőrzése a laborban GDB-vel (info registers) történik. Ezt a [a067](a067.html) alfejezet részletesen tárgyalja.

16.3.8 Tipikus hibák és ellenpróbák

  1. „A firmware elindul, de azonnal HardFault-ba esik.” Gyakori ok: a vektortábla nincs a 0-s címen, vagy a linker script másik szekciót tett oda előbb. Ellenőrzés: arm-none-eabi-objdump -h lab-a063.elf — a .vectors szekció VMA-ja legyen 0x00000000. Ha nem, a SECTIONS sorrendet vagy a KEEP-et kell módosítani.

  2. „A PUSH utasítás BusFault-ot okoz.” A kezdeti SP rossz helyre mutat — tipikusan az SRAM-on kívülre, például egy nem inicializált vagy rossz méretű régióba. Ellenőrzés: a [0x00000000] szó (objdump -s -j .vectors), illetve a linker script LENGTH értéke.

  3. „A QEMU elfogadja a binárist, de natív MPS2+-on nem indul.” A QEMU-memóriamodell és a fizikai tábla memóriatérképe eltérhet (pl. SSRAM méret). Az ilyen eltéréseket külön kell jelölni; a QEMU-eredmény nem helyettesíti a fizikai validálást.

Az ellenpróba minden esetben ugyanaz: gyanú → adatgyűjtés (objdump -h, objdump -s, GDB info registers) → egyetlen változtatás → újrafuttatás.

16.3.9 Feladatok

1. feladat (magyarázó). Egy kolléga ezt a MEMORY definíciót adta: FLASH (rx) : ORIGIN = 0x20000000, LENGTH = 1M. Magyarázd el, mi a hiba, és mi fog történni a reset után.

2. feladat (implementációs). Módosítsd a fenti lab-a063-vectors.s vektortáblát úgy, hogy a verem a 4 MiB-os kanonikus SRAM-tartomány (0x20000000–0x203FFFFF) tetejéről induljon, 8 bájtra igazítva. Írd le, melyik szót kell megváltoztatni, miért marad érvényben a vektorok sorrendje, és miért nem szabad a 0x20400000-tól kezdődő területet második veremblokkként használni.

3. feladat (hibakeresés/mérés). A firmware-ed qemu-system-arm -machine mps2-an385 alatt elindul, de azonnal HardFault-ba esik. Írj egy lépéslistát, amivel gdb-multiarch + objdump -h segítségével eldöntöd, hogy a vektortábla rossz helyen van-e, vagy a kezdeti SP értéke rossz.

16.3.10 Megoldások

1. megoldás. A 0x20000000 az SRAM régió kezdete, nem a Code régió. A reset szekvencia a 0x00000000-s címről olvassa az SP-t és a PC-t, nem a 0x20000000-ról. Következmény: a mag a 0-s címen lévő (esetleg törölt vagy véletlen) szavakat tölti be; tipikusan HardFault vagy UsageFault az első utasításnál, mielőtt bármit is kiírna. Javítás: ORIGIN = 0x00000000.

2. megoldás. Csak az első .word sor értékét kell módosítani: 0x20000000 + 4 MiB = 0x20400000. Ez a tartomány utáni első cím (kizárólagos felső határ), és ez a helyes kezdeti SP. A Cortex-M verme „full descending”: a PUSH előbb csökkenti az SP-t, és csak utána ír, ezért az első mentett szó a 0x203FFFFC-re kerül, ami még a tartományon belül van. A 0x20400000 8-cal (sőt 16-tal) osztható, így teljesül az AAPCS 8 bájtos veremigazítási szabálya a nyilvános interfészeken. A vektorok sorrendje változatlan marad, csak az SP szó értéke változik. A 0x20400000–0x207FFFFF terület nem második blokk, hanem az alsó 4 MiB tükre: egy oda tett verem a .data/.bss bájtjait írná felül egy másik címen keresztül.

3. megoldás. Lépések: (a) arm-none-eabi-objdump -h build/lab-a063.elf — nézd meg a .vectors VMA-ját; ha nem 0x00000000, a linker script a hibás. (b) objdump -s -j .vectors — az első szó legyen érvényes SRAM-cím (0x20xxxxxx), a második a Reset_Handler címe, páratlanul. (c) gdb-multiarch + target remote :3333 (a QEMU-t -S -gdb tcp::3333-mal indítva) — a reset utáni, első utasítás előtti állapot a fenti GDB-lépésekkel: ha SP és PC a vektortáblából várt értéktől eltér, akkor vagy a betöltés rossz (QEMU -kernel vs. -device loader), vagy a szekció rossz helyen van. Ha PC jó, de máshol faultol, akkor az SRAM mérete/igazítása a gyanús.

16.3.11 Rövid összefoglaló

A Cortex-M3 fix, architektúra-szintű memóriatérképet használ: 0x00000000-tól a Code régió, 0x20000000-tól az SRAM, 0x40000000-tól a periféria, 0xE0000000-tól a mag belső perifériái (PPB). A régiókat a cím felső 3 bitje választja el, egyenként 512 MB-os tartományban. Reset után a mag az első szót az MSP-be tölti, a második szó bit0-ját az EPSR.T-be, a bit0 nélküli értékét a PC-be, LR-t 0xFFFFFFFF-re állítja, és privilegizált Thread módban, IPSR = 0 mellett indul; a main() csak ezután, a reset-handler által hívva jelenik meg. QEMU mps2-an385 alatt a 4 MiB Code (FLASH nevű, de betöltött SSRAM) / 4 MiB kanonikus SRAM (0x20400000-tól tükör) / 0x40000000-ás periféria-baseline az irányadó, de a konkrét periféria-offseteket és a QEMU-machine verzióját a generálás idején ellenőrizni szükséges.

Továbbhasznált definíciók: - memóriatérkép (memory map): a 32 bites címtér hivatalos felosztása funkciók (Code/SRAM/Peripheral/PPB) szerint. - reset-vektor: a 0x00000004 címen lévő szó, amely a reset-handler belépési címét tartalmazza. - bare-metal futási modell: nincs operációs rendszer; a linker script és a startup kód rendezi el a címtér használatát.

16.3.12 Források és ellenőrzési hiányok

Az alábbiak dokumentációs kiindulópontok (forrásállapot: nem megnyitott, lásd az Olvasói útmutató jelöléseit):

Ellenőrzési hiányok (jelölve): - Az mps2-an385 konkrét periféria-offsetjei (melyik UART hol, FPGAIO/SCC/GPIO pontos címe) a generálás idején ellenőrizendők a QEMU hw/arm/mps2.c forrása és a hivatalos MPS2+ dokumentáció alapján. A QEMU-machine definíció verzióról verzióra változhat. - Az SRAM-tükör (0x20400000–0x207FFFFF = a 0x20000000–0x203FFFFF aliasa) a lektor által a QEMU 8.2.2 hw/arm/mps2.c forrásában ellenőrzött állapot; más QEMU-verzióban a monitor info mtree parancsával erősítendő meg. - A reset szekvencia lépései (MSP, PC és T-bit a reset-vektorból, LR, privilegizált Thread mód, IPSR = 0) az Armv7-M ARM-ben rögzítettek (a Cortex-M3 útmutató is Thread módot ír). A közölt GDB-lépéseket ebben a munkafolyamatban nem futtattuk QEMU alatt; a $control regiszter elérhetősége QEMU- és GDB-verziófüggő. A vektortábla-tulajdonságokat (bit0 = 1, páros végrehajtási cím) a helyettesítő eszközlánccal épített ELF-en ellenőriztük.