Kysymys:
ARM Cortex A9: n kriittisten osien toteuttaminen
CodePoet
2014-12-06 02:20:47 UTC
view on stackexchange narkive permalink

Siirrän vanhaa koodia ARM926-ytimestä CortexA9: een. Tämä koodi on baremetali eikä sisällä käyttöjärjestelmää tai vakiokirjastoja, kaikki mukautettuja. Minulla on vika, joka näyttää liittyvän kilpailutilanteeseen, joka on estettävä koodin kriittisellä osioinnilla.

Haluan palautetta lähestymistavastani nähdäksesi, eivätkö kriittiset osiot ole toteutettu oikein tässä suorittimessa. Käytän GCC: tä. Epäilen, että siinä on hienovarainen virhe.

Onko olemassa myös avoimen lähdekoodin kirjastoa, jossa on tämän tyyppisiä primitiivejä ARM: lle (tai jopa hyvä kevyt spinlock / semephore-kirjasto)?

  #define ARM_INT_KEY_TYPE allekirjoittamaton int # define ARM_INT_LOCK (avain_) \ asm haihtuva (\ "mrs% [avain], cpsr \ n \ t" \ "orr r1,% [avain], # 0xC0 \ n \ t "\" msr cpsr_c, r1 \ n \ t ": [avain]" = r "(avain_) ::" r1 "," cc "); # määritä ARM_INT_UNLOCK (avain_) asm haihtuva (" MSR cpsr_c,% 0 "::" r "(avain_))  

Koodia käytetään seuraavasti:

  / * lukitus keskeyttää * / ARM_INT_KEY_TYPE-avaimen ; ARM_INT_LOCK (avain); <access -rekisterit, jaetut globaalit jne. ... >ARM_INT_UNLOCK (avain);  

Avaimen tarkoituksena on sallia sisäkkäiset kriittiset osiot, ja näitä käytetään toimintojen alussa ja lopussa luoda uudelleenkäynnistyviä toimintoja.

Kiitos!

+1 koodaamiseen kokoonpanossa niin korkealle ytimelle.Voisiko tämä joka tapauksessa liittyä etuoikeustiloihin?
viittaus osoitteeseen http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s03s02.html älä tee sitä upotetussa asm btw: ssä.tee siitä toiminto kuten artikkelissa.
En tiedä mitään ARM: sta, mutta olettaa, että mutex (tai mikä tahansa ristisäikeinen tai ristiprosessinen synkronointitoiminto), sinun tulisi käyttää "muisti" -huijausta varmistaaksesi, että a) kaikki rekisterien välimuistissa olevat muistiarvot huuhdellaantakaisin muistiin * ennen * asm: n suorittamista ja b) kaikki muistin arvot, joihin pääsee sen jälkeen, kun asm ladataan uudelleen.Huomaa, että puhelun suorittamisen (kuten HuStmpHrrr suosittelee) pitäisi olla epäsuorasti suoritettava tämä huijaus sinulle.
Vaikka en vieläkään puhu ARMia, rajoituksesi avaimelle eivät näytä oikeilta.Koska sanot, että tätä on tarkoitus käyttää uudelleenkäyntiin, sen ilmoittaminen lukoksi "= r" näyttää epäilyttävältä.'=' tarkoittaa, että aiot korvata sen, eikä nykyinen arvo ole merkityksellinen.Vaikuttaa todennäköisemmältä, että aiot käyttää + -merkkiä aikomuksesi päivittää nykyinen arvo.Ja vielä kerran lukituksen avaamiseksi, luetteloiminen syötteeksi kertoo gcc: lle, ettet aio muuttaa sitä, mutta jos en erehdy, teet (vaihdat sen).Oletan, että tämä pitäisi myös olla "+" -lähtö.
Olen melko varma, että sinun on käytettävä `ldrex` ja` strex` tehdäksesi sen oikein.Tässä [verkkosivusto] (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344h/ch08s05s03.html) näyttää, miten `` ldrex '' - ja `` strex`` -viestejä käytetääntoteuttaa spinlock.
Haluatko ytimessä _ yksinään_, haluatko suojaa itsesi ennalta estämiseltä?Muussa tapauksessa, jos yrität synkronoida useiden ytimien tai DMA-oheislaitteiden välillä, keskeytys ei toimi lainkaan - tarvitset edellä mainitut yksinoikeudet _ asianmukaisilla esteillä_ ja huolellisen ajatuksen välimuistin johdonmukaisuudesta.
Koodi näyttää hyvältä.Mikä saa sinut ajattelemaan miljoonista koodeista, joita siirrettysi nämä 4 riviä ovat syyllisiä?
Vaikuttaa siltä, että kysymys sopii paremmin SO: lle kuin EE: lle
Voitteko kirjoittaa testitapauksia - esimerkiksi suorittaa matalan prioriteetin tehtävä, joka kirjoittaa puskuriin, ja aloittaa sitten korkeamman prioriteetin, joka keskeyttää sen?Käännetäänkö tappi jonnekin, kun kiista tapahtuu?Poista kriittinen osa ja katso, miten asiat menevät etelään, ja laita se sitten takaisin ongelman korjaamiseksi?
Neljä vastused:
supercat
2014-12-08 22:42:08 UTC
view on stackexchange narkive permalink

Kriittisen osan käsittelyn vaikein osa ilman käyttöjärjestelmää ei ole itse luoda mutex, vaan selvittää mitä pitäisi tapahtua, jos koodi haluaa käyttää resurssia, jota ei tällä hetkellä ole käytettävissä. Yksinoikeudella ladatut ja ehdolliset-myymälä-yksinoikeudet-ohjeiden avulla on melko helppoa luoda "vaihto" -toiminto, joka, kun osoitin annetaan kokonaislukulle, tallentaa atomisesti uuden arvon, mutta palauttaa sen, mitä teräväpiirtoluku sisältää: p>

  int32_t atomi_vaihto (int32_t * dest, int32_t uusi_arvo) {int32_t vanha_arvo; tee {vanha_arvo = __LDREXW (&dest); } while (__ STREXW (uusi_arvo, &dest); palauta vanha_arvo;}  

Edellä mainitun kaltaisen toiminnon avulla mutex voidaan syöttää helposti esimerkiksi

  if (atomic_swap (&mutex, 1) == 0) {... tee juttuja mutexissa ...; mutex = 0; // Jätä mutex} muuta {... ei voitu saada mutexia ...}  

Käyttöjärjestelmän puuttuessa suurin vaikeus on usein "ei voitu saada Mutex-koodia". Jos keskeytys tapahtuu, kun Mutex-vartioitu resurssi on varattu, voi olla tarpeen Pyydä keskeytyksen käsittelykoodia asettamaan lippu ja tallentamaan tietoja osoittamaan, mitä se halusi tehdä, ja sitten sinulla on kaikki pääkaltainen koodi, joka hankkii mutex-tarkistuksen aina, kun se aikoo vapauttaa mutexin nähdäksesi, halusiko keskeytys tehdä jotain samalla kun mutexia pidettiin, ja jos niin, suorita toiminto keskeytyksen puolesta.

Vaikka on mahdollista välttää ongelmia keskeyttäjien kanssa, jotka haluavat käyttää mutex-suojattuja resursseja, yksinkertaisesti poistamalla keskeytykset käytöstä (ja todellakin keskeyttävät häiriöt voivat poistaa minkäänlaisen mutexin tarpeen), yleensä on suositeltavaa välttää keskeytysten poistaminen käytöstä kauemmin kuin on välttämätöntä.

Hyödyllinen kompromissi voi olla lipun käyttö kuten yllä on kuvattu, mutta sinulla on oltava päälinjakoodi, joka vapauttaa mykistyskytkimet ja tarkista edellä mainitut liput juuri ennen kuin teet niin (ota keskeytykset uudelleen käyttöön mykistyksen vapautuksen jälkeen ). Tällainen lähestymistapa ei vaadi keskeytysten jättämistä pois käytöstä pitkään, mutta suojaa mahdollisuudelta, että jos päälinjan koodi testaa keskeytyksen lipun mutexin vapauttamisen jälkeen, on olemassa vaara, että lipun näkemisen ja sen ajan välillä toimii sen perusteella, se saatetaan saada ennalta muulla koodilla, joka hankkii ja vapauttaa mutexin ja toimii keskeytyslippuun; Jos päälinjakoodi ei testaa keskeytyksen lippua mutexin vapauttamisen jälkeen, keskeytys, joka tapahtuu juuri ennen päälinjan koodin vapauttamista, voi mykistää estää, mutta päälinja ei huomaa sitä.

Tärkeintä on joka tapauksessa keino, jolla koodilla, joka yrittää käyttää mutex-vartioitua resurssia, kun se ei ole käytettävissä, on mahdollisuus toistaa yritys, kun resurssi on vapautettu.

artless noise
2014-12-07 21:12:42 UTC
view on stackexchange narkive permalink

Tämä on raskas tapa tehdä kriittisiä osioita; Poista keskeytykset käytöstä. Se ei välttämättä toimi, jos järjestelmässäsi on / käsittelee datavirheitä. Se lisää myös keskeytysviivettä. Linux irqflags.h -palvelussa on joitain makroja, jotka käsittelevät tätä. Ohjeet cpsie ja cpsid voivat olla hyödyllisiä; Ne eivät kuitenkaan tallenna tilaa eivätkä salli pesimistä. cps ei käytä rekisteriä.

Cortex-A -sarjassa ldrex / strex ovat tehokkaampia ja voivat työskennellä muodostaakseen mutex kriittiselle osalle tai niitä voidaan käyttää lukitsematon algoritmien kanssa kriittisen osan poistamiseksi.

Joissakin mielessä ldrex / strex näyttävät olevan ARMv5 swp . Niiden toteuttaminen käytännössä on kuitenkin paljon monimutkaisempaa. Tarvitset toimivan välimuistin, ja ldrex / strex -kohdemuistin on oltava välimuistissa. ldrex / strex -kohdan ARM-dokumentaatio on melko hämärä, koska he haluavat mekanismien toimivan muilla kuin Cortex-A-suorittimilla. Cortex-A: lle mekanismi paikallisen suorittimen välimuistin pitämiseksi synkronoituna muiden suorittimien kanssa on kuitenkin sama, jota käytetään ldrex / strex -ohjeiden toteuttamiseen. Cortex-A -sarjan vararake ( ldrex / strex varatun muistin koko) on sama kuin välimuistirivi; sinun on myös kohdistettava muisti välimuistiriville, jos aiot muuttaa useita arvoja, kuten kaksoislinkitetyn luettelon kanssa.

Epäilen, että siinä on hienovarainen virhe.

  mrs% [avain], cpsrorr r1,% [avain], # 0xC0; asiayhteys tässä? msr cpsr_c, r1  

Sinun on varmistettava, että jaksoa ei voi koskaan tyhjentää . Muuten saatat saada kaksi avain -muuttujaa, joiden keskeytykset ovat käytössä, ja lukituksen vapautus on väärä. Voit käyttää swp -komentoa avain -muistin kanssa varmistaaksesi yhdenmukaisuuden ARMv5: n kanssa, mutta tämä ohje on vanhentunut Cortex-A: ssa ldrex / strexin hyväksi koska se toimii paremmin monen suorittimen järjestelmissä.

Kaikki tämä riippuu siitä, millainen ajoitus järjestelmälläsi on. Kuulostaa siltä, ​​että sinulla on vain päälinjat ja keskeytykset. Tarvitset usein kriittisen osan primitiivejä, jotta sinulla olisi joitain koukkuja ajastimeen riippuen siitä, minkä tasojen (järjestelmä / käyttäjä tila / jne.) Haluat kriittisen osan toimia.

Onko olemassa myös avoimen lähdekoodin kirjastoa, jossa on tämän tyyppisiä primitiivejä ARM: lle (tai jopa hyvä kevyt spinlock- / semephore-kirjasto)?

Tätä on vaikea kirjoittaa kannettavalla tavalla. Eli tällaisia ​​kirjastoja voi olla joillekin ARM-suorittimien versioille ja tietyille käyttöjärjestelmille.

Brian Silverman
2019-01-04 10:48:04 UTC
view on stackexchange narkive permalink

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



Tämä Q & A käännettiin automaattisesti englanniksi.Alkuperäinen sisältö on saatavilla stackexchange-palvelussa, jota kiitämme cc by-sa 3.0-lisenssistä, jolla sitä jaetaan.
Loading...