В
Laitteistoon tulee SPI-liitännän kautta kytketty SD-kortti sekä UART. Ohjelmistoosassa BootROM korvataan xip
päälle sdboot
ja itse asiassa seuraavat latausvaiheet on lisätty (SD-kortille).
Laitteiston viimeistely
Joten, tehtävä: sinun on vaihdettava "isoon" ytimeen ja kytkettävä UART (Vadelmalta) ja SD-sovitin (käytimme Catalexin korttia, jossa on kuusi nastaa: GND, VCC, MISO, MOSI, SCK, CS) .
Periaatteessa kaikki oli melko yksinkertaista. Mutta ennen kuin tajusin tämän, minua heitettiin hieman puolelta toiselle: edellisen kerran päätin, että minun on vain sekoitettava System
vähän niin kuin HasPeripheryUART
(ja toteutus vastaavasti), sama SD-kortille - ja kaikki on valmis. Sitten päätin nähdä, kuinka se toteutettiin "vakavassa" suunnittelussa. Joten mitä vakavaa tässä on? Arty ei ilmeisesti sovi - hirviö jää unleahshed.DevKitConfigs
. Ja yhtäkkiä kävi ilmi, että kaikkialla oli peittokuvia, jotka lisättiin parametreilla avaimilla. Luulen, että tämä on luultavasti erittäin joustava ja konfiguroitavissa, mutta haluaisin ainakin ajaa jotain ensin... Eikö sinulla ole sama asia, vain yksinkertaisempi ja ärsyttävämpi? .. Silloin törmäsin vera.iofpga.FPGAChip
Microsemi FPGA:lle ja purin sen heti lainauksia varten ja yritin tehdä omaa toteutusta analogisesti, onneksi on enemmän tai vähemmän koko "emolevyn asettelu" yhdessä tiedostossa.
Kävi ilmi, että sinun tarvitsee vain lisätä System.scala
linja
class System(implicit p: Parameters) extends RocketSubsystem
...
with HasPeripherySPI
with HasPeripheryUART
...
{
val tlclock = new FixedClockResource("tlclk", p(DevKitFPGAFrequencyKey))
...
}
class SystemModule[+L <: System](_outer: L)
extends RocketSubsystemModuleImp(_outer)
...
with HasPeripheryUARTModuleImp
with HasPeripheryGPIOModuleImp
...
Viiva luokan rungossa System
lisää tietoa taajuudesta, jolla tämä SoC:n osa toimii dts-tiedostoon. Ymmärtääkseni DTS/DTB on sulautettujen laitteiden plug-and-play-tekniikan staattinen analogi: dts-kuvauspuu käännetään binääriseksi dtb-tiedostoksi ja käynnistyslatain siirtää sen ytimeen, jotta se voi määrittää laitteisto. Mielenkiintoista, ilman linjaa tlclock
kaikki syntetisoituu täydellisesti, mutta BootROMin kääntäminen (muistutan, nyt tämä on jo sdboot
) ei toimi - käännösprosessin aikana se jäsentää dts-tiedoston ja luo otsikon makrolla TL_CLK
, jonka ansiosta hän pystyy konfiguroimaan ulkoisten liitäntöjen taajuusjakajat oikein.
Sinun on myös korjattava hieman "johdotusta":
Platform.scala:
class PlatformIO(implicit val p: Parameters) extends Bundle {
...
// UART
io.uart_tx := sys.uart(0).txd
sys.uart(0).rxd := RegNext(RegNext(io.uart_rx))
// SD card
io.sd_cs := sys.spi(0).cs(0)
io.sd_sck := sys.spi(0).sck
io.sd_mosi := sys.spi(0).dq(0).o
sys.spi(0).dq(0).i := false.B
sys.spi(0).dq(1).i := RegNext(RegNext(io.sd_miso))
sys.spi(0).dq(2).i := false.B
sys.spi(0).dq(3).i := false.B
}
Rekisteriketjut on rehellisesti sanottuna lisätty yksinkertaisesti analogisesti joidenkin muiden alkuperäisen koodin paikkojen kanssa. Todennäköisesti niiltä pitäisi suojautua dq
? En ole vielä löytänyt vastausta, mutta näyttää siltä, että muu koodi perustuu juuri tällaiseen yhteyteen.
Fyysisesti annoin yksinkertaisesti suunnittelunastat lohkon vapaisiin koskettimiin ja siirsin jännitteen valinnan hyppyjohtimen 3.3 V:iin.
SD-sovitin
Näkymä ylhäältä:
Alhaalta katsottuna:
Ohjelmiston virheenkorjaus: Työkalut
Puhutaanpa ensin käytettävissä olevista virheenkorjaustyökaluista ja niiden rajoituksista.
Minicom
Ensin meidän on jotenkin luettava, mitä käynnistyslatain ja ydin tuottavat. Tämän tekemiseksi Linuxissa (tässä tapauksessa RaspberryPi:ssä) tarvitsemme Minicom-ohjelman. Yleisesti ottaen mikä tahansa sarjaportin kanssa toimiva ohjelma käy.
Huomaa, että käynnistyksen yhteydessä portin laitteen nimi on määritettävä muodossa -D /dev/ttyS0
- vaihtoehdon jälkeen -D
. No, tärkein tieto: poistu, käytä Ctrl-A, X
. Minulla oli itse asiassa tapaus, jossa tämä yhdistelmä ei toiminut - sitten voit sanoa yksinkertaisesti viereisestä SSH-istunnosta killall -KILL minicom
.
On vielä yksi ominaisuus. Tarkemmin sanottuna RaspberryPissä on kaksi UART-porttia, ja molemmat portit voidaan jo mukauttaa johonkin: toinen Bluetoothille, toinen oletuksena tuottaa ytimen konsolin. Onneksi tämä käyttäytyminen voidaan ohittaa
Muistin uudelleenkirjoitus
Vianjäljityksessä minun oli joskus pakko testata hypoteesia lataa käynnistyslatain (anteeksi) RAM-muistiin suoraan isännältä. Ehkä tämän voi tehdä suoraan GDB:stä, mutta loppujen lopuksi seurasin yksinkertaista polkua: kopioin tarvittavan tiedoston Raspberrylle, välitin myös portin 4444 SSH:n kautta (telnet OpenOCD:stä) ja käytin komentoa load_image
. Kun teet sen, näyttää siltä, että kaikki on jäässä, mutta itse asiassa "se ei nuku, se vain vilkkuu hitaasti": Se lataa tiedoston, se vain tekee sen nopeudella pari kilotavua sekunnissa.
Katkaisupisteiden asennuksen ominaisuudet
Monien ei luultavasti ole tarvinnut ajatella tätä tavallisten ohjelmien virheenkorjauksen yhteydessä, mutta keskeytyskohtia ei aina aseteta laitteistossa. Joskus keskeytyskohdan asettaminen edellyttää erityisohjeiden kirjaamista tilapäisesti oikeaan paikkaan suoraan konekoodiin. Esimerkiksi standardikomentoni toimi näin b
GDB:ssä. Seuraavassa on seuraavat asiat:
- BootROMin sisään ei voi laittaa pistettä, koska ROM
- Voit asettaa keskeytyskohdan SD-kortilta RAM-muistiin ladatulle koodille, mutta sinun on odotettava, kunnes se ladataan. Muuten emme kirjoita koodinpätkää uudelleen, mutta latausohjelma kirjoittaa uudelleen keskeytyspisteemme
Olen varma, että voit nimenomaisesti pyytää käyttämään laitteiston keskeytyskohtia, mutta niitä on kuitenkin rajoitettu määrä.
Nopea BootROM-vaihto
Virheenkorjauksen alkuvaiheessa halutaan usein korjata BootROM ja yrittää uudelleen. Mutta on ongelma: BootROM on osa FPGA:lle ladattua suunnittelua, ja sen synteesi on muutaman minuutin kysymys (ja tämä tapahtuu sen jälkeen, kun itse BootROM-kuva on käännetty melkein välittömästi C:stä ja Assembleristä...). Onneksi todellisuudessa kaikki paljon nopeampi: toimintojen järjestys on seuraava:
- regeneroi bootrom.mif (vaihdin MIF:ään HEX:n sijaan, koska minulla on aina ollut ongelmia HEX:n kanssa, ja MIF on Alterin alkuperäinen muoto)
- Quartusissa sanotaan
Processing -> Update Memory Initialization File
- Assembler-kohdassa (Tasks-kohdan vasemmassa sarakkeessa) -komento Aloita uudelleen
Kaikesta kaikesta - parikymmentä sekuntia.
SD-kortin valmistelu
Kaikki täällä on suhteellisen yksinkertaista, mutta sinun on oltava kärsivällinen ja sinulla on oltava noin 14 Gt levytilaa:
git clone https://github.com/sifive/freedom-u-sdk
git submodule update --recursive --init
make
Sen jälkeen sinun on asetettava puhdas, tai pikemminkin sellainen, joka ei sisällä mitään tarpeellista, SD-kortti ja suoritettava
sudo make DISK=/dev/sdX format-boot-loader
… Missä sdX
— kortille määritetty laite. HUOMIO: kortin tiedot poistetaan, ylikirjoitetaan ja yleensä! Koko kokoonpanoa tuskin kannattaa tehdä alhaalta sudo
koska silloin kaikki rakennetut esineet kuuluvat root
, ja kokoonpano on tehtävä alhaalta sudo
jatkuvasti.
Tuloksena on GPT:ssä merkitty kortti, jossa on neljä osiota, joista yhdessä on FAT uEnv.txt
ja käynnistyskuva FIT-muodossa (sisältää useita alikuvia, jokaisella on oma latausosoite), toinen osio on tyhjä, sen oletetaan olevan alustettu Ext4 Linuxille. Vielä kaksi jaksoa - salaperäinen: Yhdessä U-Boot elää (sen offset on ymmärtääkseni kovakoodattu BootROMiin), toisella sen ympäristömuuttujat näyttävät elävän, mutta en käytä niitä vielä.
Taso yksi, BootROM
Suosittu viisaus sanoo: "Jos ohjelmoinnissa tanssitaan tamburiinilla, niin elektroniikassa tanssitaan myös sammuttimella." Kyse ei ole edes siitä, että kerran melkein poltin laudan ja päätin, että "No, GND on sama matala taso." (ilmeisesti vastus ei haittaisikaan...) Kyse on enemmänkin siitä, että jos kädet eivät kasva sieltä, niin elektroniikka ei lakkaa tuomasta yllätyksiä: liitintä levylle juotettaessa en silti pystynyt juottamaan kontakteja kunnolla - videolta näkyy kuinka juote leviää suoraan koko liitännän yli, käytä vain juotoskolvia, Minulle hän "löi" satunnaisesti. No, ehkä juotos ei ollut sopiva juotosraudan lämpötilaan, ehkä jotain muuta... Yleisesti ottaen, kun näin, että minulla on jo kymmenkunta kontaktia, luovutin ja aloin virheenkorjauksen. Ja sitten se alkoi salaperäinen: Yhdistin RX/TX:n UART:sta, lataan laiteohjelmiston - se sanoo
INIT
CMD0
ERROR
No, kaikki on loogista - en yhdistänyt SD-korttimoduulia. Korjaamme tilanteen, lataamme laiteohjelmiston... Ja hiljaisuus... Miksi en muuttanut mieltäni, mutta pieni laatikko avautui juuri: yksi moduulin nasta piti kytkeä VCC:hen. Minun tapauksessani moduuli tuki 5V virransyöttöä, joten kahdesti ajattelematta liitin moduulista tulevan johdon levyn vastakkaiselle puolelle. Tämän seurauksena vinoon juotettu liitin meni vinoon ja UART-yhteys yksinkertaisesti katosi. facepalm.jpg Yleensä "huono pää ei anna lepoa jaloille", ja vinot kädet eivät anna lepoa päälle...
Tuloksena näin kauan odotetun
INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING /
Lisäksi se liikkuu ja latausilmaisin pyörii. Muistan heti kouluaikani ja MinuetOS:n rauhassa lataamisen levykkeeltä. Ellei taajuusmuuttaja hiero.
Ongelmana on, että BOOT-viestin jälkeen mitään ei tapahdu. Tämä tarkoittaa, että on aika muodostaa yhteys OpenOCD:n kautta Raspberryen, isäntäkoneen GDB:hen ja nähdä, mikä se on.
Ensinnäkin yhteyden muodostaminen GDB:llä osoitti sen välittömästi $pc
(ohjelmalaskuri, nykyisen käskyn osoite) lentää 0x0
- Tämä tapahtuu todennäköisesti useiden virheiden jälkeen. Siksi heti viestin lähettämisen jälkeen BOOT
Lisätään loputon silmukka. Tämä viivyttää häntä jonkin aikaa...
diff --git a/bootrom/sdboot/sd.c b/bootrom/sdboot/sd.c
index c6b5ede..bca1b7f 100644
--- a/bootrom/sdboot/sd.c
+++ b/bootrom/sdboot/sd.c
@@ -224,6 +224,8 @@ int main(void)
kputs("BOOT");
+ while(*(volatile char *)0x10000){}
+
__asm__ __volatile__ ("fence.i" : : : "memory");
return 0;
}
Tällaista hankalaa koodia käytetään "luotettavuuden vuoksi": kuulin jostain, että loputon silmukka on määrittelemätön käyttäytyminen, mutta kääntäjä tuskin arvaa (muistutan, että 0x10000
sijaitsee BootROM).
Vaikuttaa siltä, mitä muuta odottaa - ankaria upotettuja, millaisia lähdekoodeja on olemassa? Mutta sisään
(gdb) file builds/zeowaa-e115/sdboot.elf
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from builds/zeowaa-e115/sdboot.elf...done.
Sinun tarvitsee vain ladata ei MIF-tiedostoa tai bin, vaan alkuperäinen versio ELF-muodossa.
Nyt voit arvata n:nnellä yrityksellä osoitteen, jossa suoritus jatkuu (tämä on toinen syy, miksi kääntäjän ei olisi pitänyt arvata silmukan olevan ääretön). Tiimi
set variable $pc=0xADDR
mahdollistaa rekisteriarvon muuttamisen lennossa (tässä tapauksessa nykyisen käskyn osoitteen). Sen avulla voit muuttaa muistiin (ja muistikartoitettuihin rekistereihin) kirjoitettuja arvoja.
Lopulta tulin siihen tulokseen (en ole varma, mikä on oikein), että meillä on "SD-korttikuva väärästä järjestelmästä", ja meidän ei tarvitse mennä ladattujen tietojen alkuun, vaan 0x89800
tavua lisää:
diff --git a/bootrom/sdboot/head.S b/bootrom/sdboot/head.S
index 14fa740..2a6c944 100644
--- a/bootrom/sdboot/head.S
+++ b/bootrom/sdboot/head.S
@@ -13,7 +13,7 @@ _prog_start:
smp_resume(s1, s2)
csrr a0, mhartid
la a1, dtb
- li s1, PAYLOAD_DEST
+ li s1, (PAYLOAD_DEST + 0x89800)
jr s1
.section .rodata
Ehkä tähän vaikutti myös se, että kun ei ollut turhaa 4Gb korttia käsilläni, otin 2Gb kortin ja vaihdoin sen Makefileen satunnaisesti. DEMO_END=11718750
päälle DEMO_END=3078900
(älä etsi merkitystä tietystä merkityksestä - sellaista ei ole, se on vain, että nyt kuva on asetettu kortille).
Taso kaksi, U-boot
Nyt ollaan vielä "putoamassa", mutta olemme jo oikeassa paikassa 0x0000000080089a84
. Tässä minun on myönnettävä: itse asiassa esitys ei mene "kaikilla pysähdyksillä", vaan on osittain kirjoitettu "jälkeen", joten täällä olen jo onnistunut syöttämään oikean dtb-tiedoston SoC:stämme, korjaa se asetuksissa HiFive_U-Boot
muuttuja CONFIG_SYS_TEXT_BASE=0x80089800
(eikä 0x08000000
), jotta latausosoite vastaa todellista osoitetta. Nyt lataamme seuraavan tason kartan, toisen kuvan:
(gdb) file ../freedom-u-sdk/work/HiFive_U-Boot/u-boot
(gdb) tui en
Ja näemme:
│304 /* │
│305 * trap entry │
│306 */ │
│307 trap_entry: │
│308 addi sp, sp, -32*REGBYTES │
>│309 SREG x1, 1*REGBYTES(sp) │
│310 SREG x2, 2*REGBYTES(sp) │
│311 SREG x3, 3*REGBYTES(sp) │
Lisäksi hyppäämme rivien 308 ja 309 välillä. Eikä se ole yllättävää, kun otetaan huomioon, että sisään $sp
on tarkoitus 0xfffffffe31cdc0a0
. Valitettavasti se myös "juoksee karkuun" jatkuvasti linjan 307 takia. Yritetään siis asettaa keskeytyskohta trap_entry
ja palaa sitten kohtaan 0x80089800
(U-Bootin sisääntulopiste), ja toivotaan, ettei se vaadi rekistereiden asettelua oikein ennen hyppäämistä... Näyttää toimivan:
(gdb) b trap_entry
Breakpoint 1 at 0x80089a80: file /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S, line 308.
(gdb) set variable $pc=0x80089800
(gdb) c
Continuing.
Breakpoint 1, trap_entry () at /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S:308
(gdb) p/x $sp
$4 = 0x81cf950
Pinoosoitin on rehellisesti sanottuna niin ja näin: se osoittaa ohittaen RAM-muistin kokonaan (ellei meillä tietenkään ole vielä osoitekäännöstä, mutta toivotaan yksinkertaista vaihtoehtoa).
Yritetään korvata osoitin sanalla 0x881cf950
. Tämän seurauksena tulemme siihen tulokseen handle_trap
soitti ja soitti, ja samaan aikaan menemme sisään _exit_trap
argumentin kanssa epc=2148315240
(desimaalilukuina):
(gdb) x/10i 2148315240
0x800cb068 <strnlen+12>: lbu a4,0(a5)
0x800cb06c <strnlen+16>: bnez a4,0x800cb078 <strnlen+28>
0x800cb070 <strnlen+20>: sub a0,a5,a0
0x800cb074 <strnlen+24>: ret
0x800cb078 <strnlen+28>: addi a5,a5,1
0x800cb07c <strnlen+32>: j 0x800cb064 <strnlen+8>
0x800cb080 <strdup>: addi sp,sp,-32
0x800cb084 <strdup+4>: sd s0,16(sp)
0x800cb088 <strdup+8>: sd ra,24(sp)
0x800cb08c <strdup+12>: li s0,0
Aseta keskeytyskohta strnlen
, jatkamme ja katsomme:
(gdb) bt
#0 strnlen (s=s@entry=0x10060000 "", count=18446744073709551615) at lib/string.c:283
#1 0x00000000800cc14c in string (buf=buf@entry=0x881cbd4c "", end=end@entry=0x881cc15c "", s=0x10060000 "", field_width=<optimized out>, precision=<optimized out>, flags=<optimized out>) at lib/vsprintf.c:265
#2 0x00000000800cc63c in vsnprintf_internal (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=0x800d446e "s , epc %08x , ra %08lxn", fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lxn", args=0x881cc1a0,
args@entry=0x881cc188) at lib/vsprintf.c:619
#3 0x00000000800cca54 in vsnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lxn", args=args@entry=0x881cc188) at lib/vsprintf.c:710
#4 0x00000000800cca68 in vscnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lxn", args=args@entry=0x881cc188) at lib/vsprintf.c:717
#5 0x00000000800ccb50 in printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lxn") at lib/vsprintf.c:792
#6 0x000000008008a9f0 in _exit_trap (regs=<optimized out>, epc=2148315240, code=<optimized out>) at arch/riscv/lib/interrupts.c:92
#7 handle_trap (mcause=<optimized out>, epc=<optimized out>, regs=<optimized out>) at arch/riscv/lib/interrupts.c:55
#8 0x0000000080089b10 in trap_entry () at /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S:343
Backtrace stopped: frame did not save the PC
Näyttää olevan, _exit_trap
haluaa antaa virheenkorjaustietoja tapahtuneesta poikkeuksesta, mutta hän ei voi. Joten jotenkin lähteitämme ei näytetä uudelleen. set directories ../freedom-u-sdk/HiFive_U-Boot/
NOIN! Nyt esillä!
Suoritetaan se uudelleen ja katsotaan pinon jäljityksestä alkuperäisen ongelman syy, joka aiheutti ensimmäisen virheen (mcause == 5
). Jos ymmärsin oikein mitä kirjoitettiin Load access fault
. Syy näyttää olevan tässä
arch/riscv/cpu/HiFive/start.S:
call_board_init_f:
li t0, -16
li t1, CONFIG_SYS_INIT_SP_ADDR
and sp, t1, t0 /* force 16 byte alignment */
#ifdef CONFIG_DEBUG_UART
jal debug_uart_init
#endif
call_board_init_f_0:
mv a0, sp
jal board_init_f_alloc_reserve
mv sp, a0
jal board_init_f_init_reserve
mv a0, zero /* a0 <-- boot_flags = 0 */
la t5, board_init_f
jr t5 /* jump to board_init_f() */
$sp
on sama väärä merkitys ja sisällä board_init_f_init_reserve
tapahtuu virhe. Tämä näyttää olevan syyllinen: muuttuja, jolla on yksiselitteinen nimi CONFIG_SYS_INIT_SP_ADDR
. Se on määritelty tiedostossa HiFive_U-Boot/include/configs/HiFive-U540.h
. Jossain vaiheessa jopa ajattelin, että ehkä, no, pitäisikö minun lisätä prosessorille käynnistyslatain - ehkä olisi helpompi korjata prosessoria vähän? Mutta sitten huomasin, että se oli enemmän kuin artefakti, joka ei ollut täysin valmis#if 0
-erityiset asetukset toiselle muistikokoonpanolle, ja voit yrittää tehdä tämän:
diff --git a/include/configs/HiFive-U540.h b/include/configs/HiFive-U540.h
index ca89383..245542c 100644
--- a/include/configs/HiFive-U540.h
+++ b/include/configs/HiFive-U540.h
@@ -65,12 +65,9 @@
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_0
#endif
#if 1
-/*#define CONFIG_NR_DRAM_BANKS 1*/
+#define CONFIG_NR_DRAM_BANKS 1
#define PHYS_SDRAM_0 0x80000000 /* SDRAM Bank #1 */
-#define PHYS_SDRAM_1
- (PHYS_SDRAM_0 + PHYS_SDRAM_0_SIZE) /* SDRAM Bank #2 */
-#define PHYS_SDRAM_0_SIZE 0x80000000 /* 2 GB */
-#define PHYS_SDRAM_1_SIZE 0x10000000 /* 256 MB */
+#define PHYS_SDRAM_0_SIZE 0x40000000 /* 1 GB */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_0
#endif
/*
@@ -81,7 +78,7 @@
#define CONSOLE_ARG "console=ttyS0,115200 "
/* Init Stack Pointer */
-#define CONFIG_SYS_INIT_SP_ADDR (0x08000000 + 0x001D0000 -
+#define CONFIG_SYS_INIT_SP_ADDR (0x80000000 + 0x001D0000 -
GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_LOAD_ADDR 0xa0000000 /* partway up SDRAM */
Jossain vaiheessa kainalosauvojen määrä
No, suunnilleen, tässä on pieni pöytä
trosinenko@trosinenko-pc:/hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot$ git show --name-status
commit 39cd67d59c16ac87b46b51ac1fb58f16f1eb1048 (HEAD -> zeowaa-1gb)
Author: Anatoly Trosinenko <[email protected]>
Date: Tue Jul 2 17:13:16 2019 +0300
Initial support for Zeowaa A-E115FB board
M arch/riscv/Kconfig
A arch/riscv/cpu/zeowaa-1gb/Makefile
A arch/riscv/cpu/zeowaa-1gb/cpu.c
A arch/riscv/cpu/zeowaa-1gb/start.S
A arch/riscv/cpu/zeowaa-1gb/timer.c
A arch/riscv/cpu/zeowaa-1gb/u-boot.lds
M arch/riscv/dts/Makefile
A arch/riscv/dts/zeowaa-1gb.dts
A board/Zeowaa/zeowaa-1gb/Kconfig
A board/Zeowaa/zeowaa-1gb/MAINTAINERS
A board/Zeowaa/zeowaa-1gb/Makefile
A board/Zeowaa/zeowaa-1gb/Zeowaa-A-E115FB.c
A configs/zeowaa-1gb_defconfig
A include/configs/zeowaa-1gb.h
Yksityiskohdat löytyvät osoitteesta
Kuten kävi ilmi, tällä SiFive-kortilla joidenkin laitteiden rekistereillä on eri osoitteet. Kävi myös ilmi, että U-Boot on määritetty Kconfig-mekanismilla, joka on jo tuttu Linux-ytimestä - voit esim. make menuconfig
, ja edessäsi tulee kätevä tekstikäyttöliittymä, joka näyttää parametrien kuvaukset by ?
jne. Yleisesti ottaen, kun on mukulannut yhteen kuvauksen kolmannesta kahden levyn kuvauksista, heittäen sieltä kaikenlaisia tekeellisiä PLL-uudelleenkonfigurointeja (ilmeisesti tämä liittyy jotenkin ohjaukseen isäntätietokoneesta PCIe: n kautta, mutta tämä ei ole varmaa) , Sain jonkinlaisen laiteohjelmiston, joka oikean sään Marsissa antoi minulle UART:n kautta viestin mistä commit hashista se on koottu ja kuinka paljon DRAMia minulla on (mutta kirjoitin tämän tiedon otsikkoon).
Harmi vain, että tämän jälkeen kortti yleensä lakkasi vastaamasta prosessorin JTAGin kautta, ja lataaminen SD-kortilta ei valitettavasti ole nopeaa minun asetuksissani. Toisaalta joskus BootROM antoi viestin, että ERROR
, ei käynnistynyt, ja U-Boot ilmestyi välittömästi. Silloin se valkeni minulle: ilmeisesti, kun bittivirta on käynnistetty uudelleen FPGA:han, muistia ei tyhjennetä, sillä ei ole aikaa "harjoitella" jne. Lyhyesti sanottuna voit yksinkertaisesti, kun viesti tulee näkyviin LOADING /
muodosta yhteys debuggeriin ja komentoon set variable $pc=0x80089800
, ohittaen näin tämän pitkän latauksen (tietenkin olettaen, että viime kerralla se meni rikki niin aikaisin, ettei se ehtinyt ladata mitään alkuperäisen koodin päälle).
Onko muuten normaalia, että prosessori jähmettyy kokonaan eikä JTAG-debuggeri voi muodostaa yhteyttä siihen viesteillä?
Error: unable to halt hart 0
Error: dmcontrol=0x80000001
Error: dmstatus =0x00030c82
Joten, odota! Olen jo nähnyt tämän! Jotain vastaavaa tapahtuu, kun TileLink on umpikujassa, enkä jotenkin luota muistiohjaimen kirjoittajaan - kirjoitin sen itse... Yhtäkkiä ensimmäisen onnistuneen prosessorin uudelleenrakentamisen jälkeen ohjaimen muokkaamisen jälkeen näin:
INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING
BOOT
U-Boot 2018.09-g39cd67d-dirty (Jul 03 2019 - 13:50:33 +0300)
DRAM: 1 GiB
MMC:
BEFORE LOAD ENVBEFORE FDTCONTROLADDRBEFORE LOADADDRIn: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 3
Tähän outoon linjaan ennen In: serial
älä kiinnitä huomiota - yritin ymmärtää riippuvalla prosessorilla, toimiiko se oikein ympäristön kanssa. Mitä tarkoitat "Se on roikkunut näin kymmenen minuuttia"? Ainakin se onnistui muuttamaan ja siirtymään käynnistysvalikkoon! Pieni poikkeama: vaikka U-Boot ladataan ensimmäiset 2^24 tavua SD-kortilta, se käynnistyessään kopioi itsensä kauempana olevaan osoitteeseen, joka on joko kirjoitettu asetusten otsikkoon tai yksinkertaisesti korkeampiin osoitteisiin. RAM, ja suorittaa ELF relocation -hahmot ja siirtää ohjauksen sinne. Joten: näyttää siltä, että läpäisimme tämän tason ja saimme bonuksen, että prosessori ei roikkunut tiukasti sen jälkeen.
Joten miksi ajastin ei toimi? Näyttää siltä, että kello ei jostain syystä toimi...
(gdb) x/x 0x0200bff8
0x200bff8: 0x00000000
Mitä jos käännät nuolia käsin?
(gdb) set variable *0x0200bff8=310000000
(gdb) c
sitten:
Hit any key to stop autoboot: 0
MMC_SPI: 0 at 0:1 hz 20000000 mode 0
Johtopäätös: kello ei tiki. Tästä syystä näppäimistön syöttö ei todennäköisesti toimi:
HiFive_U-Boot/cmd/bootmenu.c:
static void bootmenu_loop(struct bootmenu_data *menu,
enum bootmenu_key *key, int *esc)
{
int c;
while (!tstc()) {
WATCHDOG_RESET();
mdelay(10);
}
c = getc();
switch (*esc) {
case 0:
/* First char of ANSI escape sequence 'e' */
if (c == 'e') {
*esc = 1;
*key = KEY_NONE;
}
break;
case 1:
/* Second char of ANSI '[' */
if (c == '[') {
...
Ongelmaksi tuli se, että olin vähän liian fiksu: lisäsin avaimen prosessorin konfiguraatioon:
case DTSTimebase => BigInt(0)
... perustuu siihen, että kommentissa sanottiin "jos et tiedä, jätä 0". Ja loppujen lopuksi WithNBigCores
Asetin sen vain 1 MHz:iin (kuten se muuten mainittiin U-Boot-kokoonpanossa). Mutta hitto, olen siisti ja tarkka: en tiedä, täällä se on 25 MHz! Loppujen lopuksi mikään ei toimi. Poistin "parannukset" ja...
Hit any key to stop autoboot: 0
MMC_SPI: 0 at 0:1 hz 20000000 mode 0
## Unknown partition table type 0
libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND
** No partition table - mmc 0 **
## Info: input data size = 34 = 0x22
Running uEnv.txt boot2...
## Error: "boot2" not defined
HiFive-Unleashed #
Voit jopa kirjoittaa komentoja! Voit esimerkiksi vihdoin arvailla pääseväsi sisään pienen tuijotuksen jälkeen mmc_spi 1 10000000 0; mmc part
, vähentää SPI-taajuutta 20 MHz:stä 10 MHz:iin. Miksi? No, 20MHz:n maksimitaajuus oli kirjoitettu konfiguraatioon, ja se on edelleen siellä. Mutta ymmärtääkseni rajapinnat ainakin täällä toimivat näin: koodi jakaa laitteistoyksikön taajuuden (minun on 25MHz kaikkialla) tavoitteella ja asettaa tuloksena olevan arvon jakajaksi vastaavassa ohjauksessa. rekisteröidy. Ongelmana on, että jos 115200Hz UART:lle on suunnilleen mitä tarvitaan, niin jos jaat 25000000 luvulla 20000000, saat 1, ts. se toimii 25 MHz:llä. Ehkä tämä on normaalia, mutta jos rajoituksia asetetaan, se tarkoittaa, että joku tarvitsee sitä (mutta tämä ei ole varmaa)... Yleensä on helpompi laittaa se alas ja jatkaa eteenpäin - pitkälle ja valitettavasti pitkään. 25 MHz ei ole Core i9.
Konsolin lähtö
HiFive-Unleashed # env edit mmcsetup
edit: mmc_spi 1 10000000 0; mmc part
HiFive-Unleashed # boot
MMC_SPI: 1 at 0:1 hz 10000000 mode 0
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00000800 0x0000ffde "Vfat Boot"
attrs: 0x0000000000000000
type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
type: data
guid: 76bd71fd-1694-4ff3-8197-bfa81699c2fb
2 0x00040800 0x002efaf4 "root"
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
type: linux
guid: 9f3adcc5-440c-4772-b7b7-283124f38bf3
3 0x0000044c 0x000007e4 "uboot"
attrs: 0x0000000000000000
type: 5b193300-fc78-40cd-8002-e86c45580b47
guid: bb349257-0694-4e0f-9932-c801b4d76fa3
4 0x00000400 0x0000044b "uboot-env"
attrs: 0x0000000000000000
type: a09354ac-cd63-11e8-9aff-70b3d592f0fa
guid: 4db442d0-2109-435f-b858-be69629e7dbf
libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND
2376 bytes read in 0 ms
Running uEnv.txt boot2...
15332118 bytes read in 0 ms
## Loading kernel from FIT Image at 90000000 ...
Using 'config-1' configuration
Trying 'bbl' kernel subimage
Description: BBL/SBI/riscv-pk
Type: Kernel Image
Compression: uncompressed
Data Start: 0x900000d4
Data Size: 74266 Bytes = 72.5 KiB
Architecture: RISC-V
OS: Linux
Load Address: 0x80000000
Entry Point: 0x80000000
Hash algo: sha256
Hash value: 28972571467c4ad0cf08a81d9cf92b9dffc5a7cb2e0cd12fdbb3216cf1f19cbd
Verifying Hash Integrity ... sha256+ OK
## Loading fdt from FIT Image at 90000000 ...
Using 'config-1' configuration
Trying 'fdt' fdt subimage
Description: unavailable
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x90e9d31c
Data Size: 6911 Bytes = 6.7 KiB
Architecture: RISC-V
Load Address: 0x81f00000
Hash algo: sha256
Hash value: 10b0244a5a9205357772ea1c4e135a4f882409262176d8c7191238cff65bb3a8
Verifying Hash Integrity ... sha256+ OK
Loading fdt from 0x90e9d31c to 0x81f00000
Booting using the fdt blob at 0x81f00000
## Loading loadables from FIT Image at 90000000 ...
Trying 'kernel' loadables subimage
Description: Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x900123e8
Data Size: 10781356 Bytes = 10.3 MiB
Architecture: RISC-V
OS: Linux
Load Address: 0x80200000
Entry Point: unavailable
Hash algo: sha256
Hash value: 72a9847164f4efb2ac9bae736f86efe7e3772ab1f01ae275e427e2a5389c84f0
Verifying Hash Integrity ... sha256+ OK
Loading loadables from 0x900123e8 to 0x80200000
## Loading loadables from FIT Image at 90000000 ...
Trying 'ramdisk' loadables subimage
Description: buildroot initramfs
Type: RAMDisk Image
Compression: gzip compressed
Data Start: 0x90a5a780
Data Size: 4467411 Bytes = 4.3 MiB
Architecture: RISC-V
OS: Linux
Load Address: 0x82000000
Entry Point: unavailable
Hash algo: sha256
Hash value: 883dfd33ca047e3ac10d5667ffdef7b8005cac58b95055c2c2beda44bec49bd0
Verifying Hash Integrity ... sha256+ OK
Loading loadables from 0x90a5a780 to 0x82000000
Okei, olemme saavuttaneet seuraavalle tasolle, mutta se on edelleen jäätävää. Ja joskus se ripottelee myös poikkeuksia. Voit nähdä syyn odottamalla koodia määritetyssä osoitteessa $pc
ja jälkeen si
olla päällä trap_entry
. Itse U-Boot-käsittelijä voi tulostaa vain mcause = 0..4, joten valmistaudu juuttumaan väärään käynnistykseen. Sitten menin asetuksiin, aloin katsoa, mitä olin muuttamassa, ja muistin: siellä conf/rvboot-fit.txt
kirjoitettu:
fitfile=image.fit
# below much match what's in FIT (ugha)
No, saatetaan kaikki tiedostot yhteen, korvataan ytimen komentorivi jollain tämmöisellä, koska epäillään, että SIF0
- tämä on lähtö jossain PCIe:n kautta:
-bootargs=console=ttySIF0,921600 debug
+bootargs=console=ttyS0,125200 debug
Ja vaihdetaan tiivistysalgoritmi SHA-256:sta MD5:een: En tarvitse salausvoimakkuutta (etenkään vianetsinnässä), se vie hirveän kauan ja eheysvirheiden havaitsemiseen latauksen aikana MD5 on liian helppoa. Mikä on lopputulos? Aloimme suorittaa edellistä tasoa huomattavasti nopeammin (yksinkertaisemman tiivistyksen ansiosta), ja seuraava avautui:
...
Verifying Hash Integrity ... md5+ OK
Loading loadables from 0x90a5a758 to 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
chosen {
linux,initrd-end = <0x00000000 0x83000000>;
linux,initrd-start = <0x00000000 0x82000000>;
riscv,kernel-end = <0x00000000 0x80a00000>;
riscv,kernel-start = <0x00000000 0x80200000>;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND
chosen {
linux,initrd-end = <0x00000000 0x83000000>;
linux,initrd-start = <0x00000000 0x82000000>;
riscv,kernel-end = <0x00000000 0x80a00000>;
riscv,kernel-start = <0x00000000 0x80200000>;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
Loading Kernel Image ... OK
Booting kernel in
3
Mutta kello ei käy...
(gdb) x/x 0x0200bff8
0x200bff8: 0x00000000
Hups, näyttää siltä, että kellon korjaaminen osoittautui plaseboksi, vaikka minusta silloin tuntui, että se auttoi. Ei, se on tietysti korjattava, mutta käännetään ensin nuolia manuaalisesti ja katsotaan mitä tapahtuu:
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=1000000
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=2000000
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x00000000bff6dbb0 in ?? ()
(gdb) set variable *0x0200bff8=3000000
(gdb) c
Continuing.
Sillä välin…
Loading Kernel Image ... OK
Booting kernel in
3
2
1
0
## Starting application at 0x80000000 ...
Ei, aion automatisoida kellon - muuten ehkä hän päättää kalibroida ajastimen siellä!
Sillä välin nykyisen ohjeen osoite osoittaa jonnekin
0000000080001c20 <poweroff>:
80001c20: 1141 addi sp,sp,-16
80001c22: e022 sd s0,0(sp)
80001c24: 842a mv s0,a0
80001c26: 00005517 auipc a0,0x5
80001c2a: 0ca50513 addi a0,a0,202 # 80006cf0 <softfloat_countLeadingZeros8+0x558>
80001c2e: e406 sd ra,8(sp)
80001c30: f7fff0ef jal ra,80001bae <printm>
80001c34: 8522 mv a0,s0
80001c36: 267000ef jal ra,8000269c <finisher_exit>
80001c3a: 00010797 auipc a5,0x10
80001c3e: 41e78793 addi a5,a5,1054 # 80012058 <htif>
80001c42: 639c ld a5,0(a5)
80001c44: c399 beqz a5,80001c4a <poweroff+0x2a>
80001c46: 72c000ef jal ra,80002372 <htif_poweroff>
80001c4a: 45a1 li a1,8
80001c4c: 4501 li a0,0
80001c4e: dc7ff0ef jal ra,80001a14 <send_ipi_many>
80001c52: 10500073 wfi
80001c56: bff5 j 80001c52 <poweroff+0x32>
ladatun Berkeley Boot Loaderin sisällä. Henkilökohtaisesti minua hämmentää tässä maininta htif
— isäntärajapinta, jota käytetään ytimen kytkettyyn käynnistämiseen (eli yhteistyössä isäntä-ARM:n kanssa), oletin, että se on erillinen. Jos kuitenkin löydät tämän toiminnon lähdekoodista, voit nähdä, että kaikki ei ole niin huonoa:
void poweroff(uint16_t code)
{
printm("Power offrn");
finisher_exit(code);
if (htif) {
htif_poweroff();
} else {
send_ipi_many(0, IPI_HALT);
while (1) { asm volatile ("wfin"); }
}
}
Tehtävä: käynnistä kello
Rekistereiden etsiminen CLINTistä johtaa meidät
val io = IO(new Bundle {
val rtcTick = Bool(INPUT)
})
val time = RegInit(UInt(0, width = timeWidth))
when (io.rtcTick) { time := time + UInt(1) }
Joka liittyy RTC:hen tai salaperäiseen MockAONiin, josta aluksi ajattelin: ”Mitä meillä on täällä? Epäselvä? Sammuta se!" Koska en vieläkään ymmärrä, millaista kellotaikuutta siellä tapahtuu, niin otan tämän logiikan käyttöön uudelleen System.scala
:
val rtcDivider = RegInit(0.asUInt(16.W)) // на всякий случай поддержу до 16ГГц, я оптимист :)
val mhzInt = p(DevKitFPGAFrequencyKey).toInt
// Преположим, частота равна целому числу мегагерц
rtcDivider := Mux(rtcDivider === (mhzInt - 1).U, 0.U, rtcDivider + 1.U)
outer.clintOpt.foreach { clint =>
clint.module.io.rtcTick := rtcDivider === 0.U
}
Matkalla kohti Linux-ytimiä
Tässä tarina on jo venynyt ja muuttunut hieman yksitoikkoiseksi, joten kuvailen sitä ylhäältä alas:
BBL oletti FDT:n läsnäolon klo 0xF0000000
, mutta korjasin sen jo! No, katsotaan uudestaan... Löysin sen HiFive_U-Boot/arch/riscv/lib/boot.c, korvattu 0x81F00000
, määritetty U-Boot-käynnistyskokoonpanossa.
Sitten BBL valitti, ettei muistia ollut. Minun polkuni oli funktiossa mem_prop
, mitä sisällä riscv-pk/machine/fdt.c: Sieltä opin, että sinun täytyy merkitä fdt ram-solmu nimellä device_type = "memory"
- Sitten ehkä prosessorin generaattori on korjattava, mutta toistaiseksi kirjoitan sen vain manuaalisesti - joka tapauksessa siirsin tämän tiedoston manuaalisesti.
Nyt sain viestin (toimitettu muotoillussa muodossa, vaunujen palautuksilla):
This is bbl's dummy_payload. To boot a real kernel, reconfigure bbl
with the flag --with-payload=PATH, then rebuild bbl. Alternatively,
bbl can be used in firmware-only mode by adding device-tree nodes
for an external payload and use QEMU's -bios and -kernel options.
Näyttää siltä, että vaihtoehdot on ilmoitettu tarpeen mukaan riscv,kernel-start
и riscv,kernel-end
DTB:ssä, mutta nollia jäsennetään. Virheenkorjaus query_chosen
osoitti, että BBL yrittää jäsentää 32-bittistä osoitetta, mutta se löytää parin <0x0 0xADDR>
, ja ensimmäinen arvo näyttää olevan vähiten merkitseviä bittejä. Lisätty osioon chosen
chosen {
#address-cells = <1>;
#size-cells = <0>;
...
}
ja korjasi arvojen luomisen: älä lisää 0x0
ensimmäinen elementti.
Näiden 100500 XNUMX yksinkertaisen vaiheen avulla on helppo seurata pingviinin putoamista:
Piilotettu teksti
Verifying Hash Integrity ... md5+ OK
Loading loadables from 0x90a5a758 to 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
chosen {
linux,initrd-end = <0x83000000>;
linux,initrd-start = <0x82000000>;
riscv,kernel-end = <0x80a00000>;
riscv,kernel-start = <0x80200000>;
#address-cells = <0x00000001>;
#size-cells = <0x00000000>;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
stdout-path = "uart0:38400n8";
};
libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND
chosen {
linux,initrd-end = <0x83000000>;
linux,initrd-start = <0x82000000>;
riscv,kernel-end = <0x80a00000>;
riscv,kernel-start = <0x80200000>;
#address-cells = <0x00000001>;
#size-cells = <0x00000000>;
bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
stdout-path = "uart0:38400n8";
};
Loading Kernel Image ... OK
Booting kernel in
3
2
1
0
## Starting application at 0x80000000 ...
bbl loader
SIFIVE, INC.
5555555555555555555555555
5555 5555
5555 5555
5555 5555
5555 5555555555555555555555
5555 555555555555555555555555
5555 5555
5555 5555
5555 5555
5555555555555555555555555555 55555
55555 555555555 55555
55555 55555 55555
55555 5 55555
55555 55555
55555 55555
55555 55555
55555 55555
55555 55555
555555555
55555
5
SiFive RISC-V Core IP
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[ 0.000000] Linux version 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc version 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Wed Jul 3 21:29:21 MSK 2019
[ 0.000000] bootconsole [early0] enabled
[ 0.000000] Initial ramdisk at: 0x(____ptrval____) (16777216 bytes)
[ 0.000000] Zone ranges:
[ 0.000000] DMA32 [mem 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] Normal [mem 0x00000000c0000000-0x00000bffffffffff]
[ 0.000000] Movable zone start for each node
[ 0.000000] Early memory node ranges
[ 0.000000] node 0: [mem 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000bfffffff]
[ 0.000000] On node 0 totalpages: 261632
[ 0.000000] DMA32 zone: 3577 pages used for memmap
[ 0.000000] DMA32 zone: 0 pages reserved
[ 0.000000] DMA32 zone: 261632 pages, LIFO batch:63
[ 0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)
(BBL näyttää logon ja ydin näyttää logon, jossa on aikaleima).
Onneksi en tiedä miten se on kaikkialla, mutta RocketChipissä, kun yhdistät debuggerin JTAGin kautta, voit saada ansoja pois laatikosta - debuggeri pysähtyy täsmälleen tässä vaiheessa.
Program received signal SIGTRAP, Trace/breakpoint trap.
0xffffffe0000024ca in ?? ()
(gdb) bt
#0 0xffffffe0000024ca in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) file work/linux/vmlinux
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from work/linux/vmlinux...done.
(gdb) bt
#0 0xffffffe0000024ca in setup_smp () at /hdd/trosinenko/fpga/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:75
#1 0x0000000000000000 in ?? ()
Backtrace stopped: frame did not save the PC
freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:
void __init setup_smp(void)
{
struct device_node *dn = NULL;
int hart;
bool found_boot_cpu = false;
int cpuid = 1;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
hart = riscv_of_processor_hartid(dn);
if (hart < 0)
continue;
if (hart == cpuid_to_hartid_map(0)) {
BUG_ON(found_boot_cpu);
found_boot_cpu = 1;
continue;
}
cpuid_to_hartid_map(cpuid) = hart;
set_cpu_possible(cpuid, true);
set_cpu_present(cpuid, true);
cpuid++;
}
BUG_ON(!found_boot_cpu); // < ВЫ НАХОДИТЕСЬ ЗДЕСЬ
}
Kuten vanha vitsi sanoi, Prosessoria ei löydy, käynnissä ohjelmistoemulointi. Tai sitten ei juokse. Kadonnut yhteen prosessoriytimeen.
/* The lucky hart to first increment this variable will boot the other cores */
atomic_t hart_lottery;
unsigned long boot_cpu_hartid;
Kiva kommentti mukana linux/arch/riscv/kernel/setup.c - eräänlainen aidan maalaus Tom Sawyer -menetelmällä. Yleensä jostain syystä tänään ei ollut voittajia, palkinto siirtyy seuraavaan arvontaan...
Ehdotan tähän lopettaa jo ennestään pitkä artikkeli.
Jatkuu. Tulee taistelu ovelan bugin kanssa, joka onnistuu piiloutumaan, jos hiipii sen päälle hitaasti yhdellä askeleella.
Tekstin lataus screencast (ulkoinen linkki):
Lähde: will.com