Näen useita mahdollisia ongelmia noissa kriittisissä osioissa. Kaikkiin näihin on varoituksia ja ratkaisuja, mutta yhteenvetona:
- Mikään ei estä kääntäjää siirtämästä koodia näiden makrojen läpi optimoinnista tai muista satunnaisista syistä.
- He tallentavat ja palauttavat osan prosessorin tilasta, jonka kääntäjä odottaa sisäisen kokoonpanon jättävän yksin (ellei toisin käydä).
- Mikään ei estä keskeytystä tapahtumasta sekvenssin keskellä ja tilan muuttamista lukemisen ja kirjoittamisen välillä.
Ensinnäkin, tarvitset ehdottomasti joitain kääntäjän muistinesteitä. Persianlahden yhteistyöneuvosto toteuttaa nämä ryöstäjinä. Pohjimmiltaan tämä on tapa kertoa kääntäjälle "Ei, et voi siirtää muistihakemuksia tämän sisäisen kokoonpanon läpi, koska se saattaa vaikuttaa muistihakemusten tulokseen." Tarvitset erityisesti "memory"
- ja "cc"
-joukot sekä alku- että lopetusmakrossa. Tämä estää muiden asioiden (kuten toimintokutsujen) järjestämisen uudelleen myös inline-kokoonpanoon nähden, koska kääntäjä tietää, että niillä voi olla muistin käyttöoikeuksia. Olen nähnyt ARC: n GCC: n pitotilan ehtokoodirekistereissä inline-kokoonpanossa "memory"
-joukon kanssa, joten tarvitset ehdottomasti "cc"
-kaappaajan.
Toiseksi nämä kriittiset kohdat säästävät ja palauttavat paljon enemmän kuin vain keskeytysten mahdollistamisen. Erityisesti he tallentavat ja palauttavat suurimman osan CPSR: stä (nykyinen ohjelman tilarekisteri) (linkki on Cortex-R4: lle, koska en löytänyt mukavaa kaaviota A9: lle, mutta sen pitäisi olla sama). Siellä on hienovaraisia rajoituksia, joiden ympärillä osavaltioita voidaan todella muokata, mutta se on täällä enemmän kuin välttämätöntä.
Tähän sisältyy muun muassa ehtokoodit (joihin ohjeiden, kuten cmp
, tulokset tallennetaan, jotta seuraavat ehdolliset ohjeet voivat vaikuttaa tulokseen). Kääntäjä on ehdottomasti hämmentynyt tästä. Tämä on helppo ratkaista käyttämällä yllä mainittua "cc"
-pilkkua. Tämä kuitenkin tekee koodin epäonnistumisesta joka kerta, joten se ei kuulosta siltä, mitä näette ongelmissa. Hieman tiksuvasta aikapommista, sillä satunnaisen muun koodin muokkaaminen saattaa saada kääntäjän tekemään jotain hieman erilaista, joka rikkoutuu tällä tavalla.
Tämä yrittää myös tallentaa / palauttaa IT-bitit, joita käytetään Thumb-ehdollisen suorituksen toteuttamiseen. Huomaa, että jos et koskaan suorita Thumb-koodia, sillä ei ole merkitystä. En ole koskaan ymmärtänyt, kuinka GCC: n inline-kokoonpano käsittelee IT-bittejä, lukuun ottamatta sitä, että se ei ole, eli kääntäjä ei saa koskaan laittaa inline-kokoonpanoa IT-lohkoon ja aina odottaa kokoonpanon päättyvän IT-lohkon ulkopuolella. En ole koskaan nähnyt GCC: n tuottavan koodia, joka rikkoo näitä oletuksia, ja olen tehnyt melko monimutkaisen sisäisen kokoonpanon voimakkaalla optimoinnilla, joten olen kohtuullisen varma, että ne pitävät paikkansa. Tämä tarkoittaa, että se ei todennäköisesti yritä muuttaa IT-bittejä, jolloin kaikki on hyvin. Näiden bittien muokkaaminen on luokiteltu "arkkitehtonisesti arvaamattomaksi", joten se voi tehdä kaikenlaisia pahoja asioita, mutta ei todennäköisesti tee mitään lainkaan.
Viimeinen tallennettujen / palautettavien bittien luokka (lukuun ottamatta keskeytyksiä todella poistavia) ovat tilabitit. Nämä eivät todennäköisesti muutu, joten sillä ei todennäköisesti ole väliä, mutta jos sinulla on koodia, joka tahallaan muuttaa tilaa, nämä keskeytysosuudet voivat aiheuttaa ongelmia. Vaihtaminen etuoikeutetun ja käyttäjätilan välillä on ainoa tapaus, jolla odotan tätä.
Kolmanneksi, mikään ei estä keskeytystä muuttamasta CPSR: n muita osia ARM_INT_LOCK
-kohdan MRS
ja MSR
välillä. Tällaiset muutokset voidaan korvata. Useimmissa kohtuullisissa järjestelmissä asynkroniset keskeytykset eivät muuta keskeytettävän koodin tilaa (mukaan lukien CPSR). Jos he tekevät, on vaikea ymmärtää mitä koodi tekee. Se on kuitenkin mahdollista (FIQ-estobitin vaihtaminen näyttää todennäköisimmältä), joten sinun on harkittava, tekeekö järjestelmäsi tämän.
Näin toteuttaisin nämä tavalla, joka ratkaisee kaikki mainitsemani mahdolliset ongelmat:
#define ARM_INT_KEY_TYPE allekirjoittamaton int
#define ARM_INT_LOCK (avain_) \
asm haihtuva (\
"rouva% [avain], cpsr \ n \ t" \
"ands% [key],% [key], # 0xC0 \ n \ t" \
"cpsid if \ n \ t": [avain] "= r" (avain_) :: "muisti", "cc");
#define ARM_INT_UNLOCK (avain_) asm volatile (\
"tst% [avain], # 0x40 \ n \ t" \
"beq 0f \ n \ t" \
"cpsie f \ n \ t" \
"0: tst% [avain], # 0x80 \ n \ t" \
"beq 1f \ n \ t" \
"cpsie i \ n \ t"
"1: \ n \ t" :: [avain] "r" (avain_): "muisti", "kopio")
Varmista, että käännät tiedostoa -mcpu = cortex-a9
, koska ainakin jotkut GCC-versiot (kuten minun) oletusarvoisesti vanhempaan ARM-suorittimeen, joka ei tue cpsie
ja cpsid
.
Käytin jas
-tunnuksia vain koodin ja
sijasta kohdassa ARM_INT_LOCK
, joten se on 16-bittinen käsky, jos sitä käytetään peukalokoodissa. "cc"
-seuraaja on joka tapauksessa välttämätön, joten siitä on ehdottomasti hyötyä suorituskyvyn / koodin koon mukaan.
0
ja 1
ovat paikallisia tunnisteita.
Näiden pitäisi olla käyttökelpoisia kaikin tavoin kuin versiosi. ARM_INT_LOCK
on yhtä nopea / pieni kuin alkuperäinen. Valitettavasti en kyennyt keksimään tapaa tehdä ARM_INT_UNLOCK
turvallisesti missä tahansa lähellä niin vähän ohjeita.
Jos järjestelmässäsi on rajoituksia, kun IRQ: t ja FIQ: t poistetaan käytöstä, tätä voidaan yksinkertaistaa.Esimerkiksi, jos ne ovat aina poissa käytöstä yhdessä, voit yhdistää yhdeksi cbz
+ cpsie, jos
näin:
#define ARM_INT_UNLOCK (avain_) asm volatile (\
"cbz% [avain], 0f \ n \ t" \
"cpsie jos \ n \ t" \
"0: \ n \ t" :: [avain] "r" (avain_): "muisti", "kopio")
Vaihtoehtoisesti, jos et välitä FIQ-laitteista ollenkaan, se on samanlainen kuin vain jättää niiden ottaminen käyttöön tai poistaminen kokonaan käytöstä.
Jos tiedät, että mikään muu ei koskaan muuta mitään muita CPSR: n tilabittejä lukituksen ja lukituksen avaamisen välillä, voit käyttää myös jatkoa jollakin, joka on hyvin samanlainen kuin alkuperäinen koodi, paitsi molemmilla "muistilla"
- ja "cc"
-joukot sekä ARM_INT_LOCK
- että ARM_INT_UNLOCK