Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Pjesa 3: Pothuajse po ngarkojmĂ« Linux nga kartela SD nĂ« RocketChip NĂ« pjesĂ«n e kaluar u implementua njĂ« kontrollues memorie mĂ« shumĂ« pak funksional, mĂ« saktĂ«sisht — njĂ« mbĂ«shtjellĂ«s mbi IP Core nga Quartus, i cili shĂ«rben si njĂ« ndĂ«rfaqs pĂ«r TileLink. Sot nĂ« rubrikĂ«n "Ne po portojmĂ« RocketChip nĂ« njĂ« bord tĂ« panjohur kinez me Cyclone" do tĂ« shihni njĂ« konsolĂ« funksionale. Procesi zgjati pak mĂ« shumĂ«: mendova se do tĂ« ngarkoja me shpejtĂ«si Linux dhe do tĂ« shkonim pĂ«rpara, por jo. NĂ« kĂ«tĂ« pjesĂ« propozoj tĂ« shohim procesin e ngarkimit tĂ« U-Boot, BBL, dhe pĂ«rpjekjet e ngathta tĂ« kernel-it tĂ« Linux pĂ«r t'u inicializuar. Por ka njĂ« konsolĂ« — ajo e U-Boot-it, dhe Ă«shtĂ« mjaft e avancuar, duke pasur shumĂ« nga ato qĂ« prisni nga njĂ« konsolĂ« tĂ« plotĂ«.

Në pjesën harduerike do të shtohet karta SD, e lidhur përmes interfesës SPI, si dhe UART. Në pjesën software BootROM do të zëvendësohet me xip në sdboot dhe, në fakt, do të shtohen fazat e ngarkimit të mëposhtme (në kartelën SD).

Përmirësimi i pjesës harduerike

Pra, detyra: duhet të kalojmë në një bërthamë "të madhe" dhe të lidhim UART (nga Raspberry) dhe adaptern e SD (u përdor një bord nga Catalex me gjashtë pinë: GND, VCC, MISO, MOSI, SCK, CS).

NĂ« parim, gjithçka ishte mjaft e thjeshtĂ«. Por para se ta kuptoja kĂ«tĂ«, u ndjeva pak e lĂ«kundur: pas herĂ«s sĂ« mĂ«parshme, vendosa se ishte e nevojshme tĂ« pĂ«rzihej pĂ«rsĂ«ri nĂ« Sistemi diçka si HasPeripheryUART (dhe nĂ« realizimin pĂ«rkatĂ«s), po ashtu pĂ«r kartelĂ«n SD — dhe gjithçka do tĂ« ishte gati. MĂ« pas vendosa tĂ« shoh se si ishte realizuar nĂ« njĂ« dizajn "tĂ« rĂ«ndĂ«sishĂ«m". Pra, çfarĂ« kemi kĂ«tu nga tĂ« rĂ«ndĂ«sishmet? Arty, duket, nuk i pĂ«rgjigjet — mbetet monstĂ«r unleahshed.DevKitConfigs. Dhe papritmas doli se kishim disa overlay tĂ« ndryshĂ«m, qĂ« shtohen pĂ«rmes parametrave tĂ« çelĂ«save. Mendoj se ndoshta Ă«shtĂ« shumĂ« fleksibĂ«l dhe konfigurueshĂ«m, por mĂ« duhet tĂ« paktĂ«n diçka pĂ«r tĂ« nisur... Por a keni diçka tĂ« ngjashme, vetĂ«m mĂ« tĂ« thjeshtĂ« dhe me defekte?.. Aty u ndesha me vera.iofpga.FPGAChip pĂ«r FPGA tĂ« Microsemi dhe menjĂ«herĂ« e kam pĂ«rdorur pĂ«r citate duke provuar tĂ« bĂ«j realizimin tim duke u bazuar nĂ« tĂ«, pĂ«r fat tĂ« mirĂ« kĂ«tu Ă«shtĂ« disi e gjitha "konstrukti i bordit tĂ« sistemit" nĂ« njĂ« skedar.

Doli, në fakt, se thjesht duhet të shtoj në System.scala rreshtat

class System(implicit p: Parameters) extends RocketSubsystem
...
  me HasPeripherySPI
  me HasPeripheryUART
...
{
  val tlclock = new FixedClockResource("tlclk", p(DevKitFPGAFrequencyKey))
  ...
}

class SystemModule[+L <: System](_outer: L)
  extends RocketSubsystemModuleImp(_outer)
...
    me HasPeripheryUARTModuleImp
    me HasPeripheryGPIOModuleImp
...

Rreshti nĂ« trupin e klasĂ«s Sistemi shton informacionin mbi frekuencĂ«n me tĂ« cilĂ«n funksionon ky pjesĂ« e SoC tonĂ« nĂ« skedarin dts. Sa kuptoj, DTS/DTB Ă«shtĂ« njĂ« ekuivalent statik i teknologjisĂ« plug-and-play pĂ«r pajisjet e integruara: struktura e pĂ«rshkrimit dts kompilohet nĂ« njĂ« skedar binar dtb dhe i dĂ«rgohet ngarkuesit pĂ«r t'i lejuar atij tĂ« konfigurojĂ« saktĂ«sisht pajisjet. Ajo qĂ« Ă«shtĂ« interesante, pa rreshtin me tlclock gjithçka sintetohet mirĂ«, por nuk do tĂ« jetĂ« e mundur tĂ« kompilojmĂ« BootROM (mĂ« kujtohet, tani do tĂ« jetĂ« tashmĂ« sdboot) — gjatĂ« procesit tĂ« kompilimit, ai analizon skedarin dts dhe krijon njĂ« header me makro TL_CLK, duke e lejuar qĂ« ai tĂ« konfigurojĂ« saktĂ«sisht ndarĂ«sit e frekuencĂ«s pĂ«r ndĂ«rfaqet e jashtme.

Po ashtu, do të nevojitet të bëjmë disa rregullime në "shtrirjen":

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
}

ZinxhirĂ«t e regjistrave, sinqerisht, janĂ« shtuar thjesht pĂ«r analogji me disa vende tĂ« tjera nĂ« kodin origjinal. Me sa duket, ata duhet tĂ« mbrojnĂ« nga metastabiliteti. Ndoshta, nĂ« disa bloke, tashmĂ« ka mbrojtje tĂ« vet, por sĂ« pari do tĂ« doja tĂ« niste tĂ« paktĂ«n "nĂ« njĂ« nivel tĂ« kualitetit tĂ« lartĂ«". Pyetja mĂ« interesante pĂ«r mua Ă«shtĂ« — pse MISO dhe MOSI janĂ« tĂ« lidhura nĂ« tĂ« ndryshme dq? ОтĐČДта я ĐżĐŸĐșа таĐș Đž ĐœĐ” ĐœĐ°ŃˆŃ‘Đ», ĐœĐŸ, ĐżĐŸŃ…ĐŸĐ¶Đ”, ĐŸŃŃ‚Đ°Đ»ŃŒĐœĐŸĐč ĐșĐŸĐŽ рассчотыĐČаДт ĐžĐŒĐ”ĐœĐœĐŸ ĐœĐ° таĐșĐŸĐ” ĐżĐŸĐŽĐșĐ»ŃŽŃ‡Đ”ĐœĐžĐ”.

Fizikisht, thjesht kam caktuar dalje të dizajnit në kontaktet e lira në bllok dhe kam zhvendosur jumperin e zgjedhjes së tensionit në 3.3V.

SD-adapteri

Pamja nga lart:

Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Pamja nga poshtë:

Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Debugimi i pjesës së softuerit: mjetet

Fillimisht do të flasim për mjetet e disponueshme të debugimit dhe kufizimet e tyre.

Minicom

SĂ« pari, do tĂ« na nevojitet ndonjĂ« mĂ«nyrĂ« pĂ«r tĂ« lexuar atĂ« qĂ« shkruan ngarkuesi dhe bĂ«rthama. PĂ«r kĂ«tĂ«, nĂ« Linux (nĂ« kĂ«tĂ« rast — nĂ« atĂ« qĂ« Ă«shtĂ« nĂ« RaspberryPi) do tĂ« na nevojitet programi Minicom. NĂ« pĂ«rgjithĂ«si, çdo program pĂ«r pĂ«rdorim me port serial Ă«shtĂ« i pĂ«rshtatshĂ«m.

Kujdes, qĂ« kur nisi, emri i pajisjes sĂ« portit duhet tĂ« jepet si -D /dev/ttyS0 — pas opsionit -D. E, informacioni kryesor: pĂ«r daljen pĂ«rdorni Ctrl-A, X. NĂ« tĂ« vĂ«rtetĂ«, kam pasur njĂ« rast kur kjo kombinim nuk punoi — atĂ«herĂ« mund tĂ« thoni nga seanca e fqinjit SSH thjesht killall -KILL minicom.

Ka një tipar tjetër. Konkretisht në RaspberryPi ka dy UART, dhe të dy portet mund të jenë tashmë të përshtatur për diçka: njëri për Bluetooth, ndërsa tjetri për defaut shfaq konsolën e bërthamës. Fatmirësisht, ky sjellje mund të rikonfigurohet. sipas këtij udhëzuesi..

Rikodimi i memories.

Gjatë depurimit, për të verifikuar hipotezën ndonjëherë më ka ndodhur që duhet ta ngarkoja ngarkuesin (më vjen keq) në memorien e përkohshme direkt nga hosti. Ndoshta, mundet që ta bëni këtë direkt nga GDB, por në fund të fundit ndoqa rrugën e thjeshtë: kopjova dosjen e nevojshme në Raspberry, kalova gjithashtu portin 4444 përmes SSH (telnet nga OpenOCD) dhe përdora komandën load_image. Kur e ekzekutoni, duket sikur gjithçka është ngrirë, por në të vërtetë «nuk fle, thjesht pala e diçka të ngadaltë»: po ngarkon dosjen, thjesht e bën këtë me një shpejtësi disa kilobajt në sekondë.

Tiparet e vendosjes së breakpoint-ëve.

Mund të mos ketë ndodhur që shumë njerëz ta mendojnë këtë gjatë depurimit të programeve normale, por pikat e ndalimit nuk vendosen gjithmonë në mënyrë harduerike. Ndonjëherë vendosja e një breakpoint-i përfshin shkrimin përkohësisht të një instruksioni të veçantë në vendin e duhur drejt në kodin e makinerisë.Për shembull, kështu vepronte komanda standarde b në GDB. Ja se çfarë rezulton nga kjo:

  • nuk mund tĂ« vendosni njĂ« pikĂ« brenda BootROM, sepse ROM
  • njĂ« pikĂ« ndalimi mbi kodin e ngarkuar nĂ« memore me SD kartĂ« mund tĂ« vendoset, por duhet tĂ« presim qĂ« tĂ« ngarkohet. NĂ« rast tĂ« kundĂ«rt, nuk do tĂ« rishkruajmĂ« njĂ« copĂ« kod, por ngarkuesi do tĂ« rishkruajĂ« breakpoint-in tonĂ«.

Jam i sigurt se mund të kërkoni qartë të përdoren pikat e ndalimit harduerike, por ato në çdo rast janë të numëruara.

Zëvendësimi i shpejtë i BootROM.

Në fazën fillestare të depurimit shpesh lind dëshira për të rregulluar BootROM dhe të provoni përsëri. Por ka një problem: BootROM është pjesë e dizajnit, i ngarkuar në FPGA, dhe sintetizimi i tij është një punë disa minutash (dhe kjo pas kompilimit pothuajse të menjëhershëm të vetë imazhit BootROM nga C dhe Assembler...). Fatmirësisht, në të vërtetë gjithçka është shumë më e shpejtë:sekuenca e veprimeve është kjo:

  • rigenĂ«ro bootrom.mif (kam kaluar nĂ« MIF nĂ« vend tĂ« HEX, sepse me HEX gjithmonĂ« kam pasur disa probleme, dhe MIF Ă«shtĂ« formati i natyrshĂ«m i Altera)
  • nĂ« Quartus tha Processing -> Update Memory Initialization File
  • nĂ« pikĂ«n Assembler (nĂ« kolonĂ«n e majtĂ« Tasks) urdhĂ«ro Start again.

PĂ«r tĂ« gjitha kĂ«to — disa dhjetĂ«ra sekonda.

Përgatitja e kartës SD.

Këtu gjithçka është mjaft e thjeshtë, por duhet të jeni të duruar dhe të keni rreth 14Gb hapësirë në disk:

git clone https://github.com/sifive/freedom-u-sdk
git submodule update --recursive --init
make

Pas kësaj, duhet të futni një kartë SD të pastër, për më saktë, që nuk përmban asgjë të nevojshme, dhe të kryeni

sudo make DISK=/dev/sdX format-boot-loader


 ku sdX — pajisja e caktuar pĂ«r kartĂ«n. KËSHILLË: tĂ« dhĂ«nat nĂ« kartĂ« do tĂ« fshihen, do tĂ« tejkalohen dhe pĂ«rgjithĂ«sisht! Nuk ka shumĂ« kuptim tĂ« bĂ«ni tĂ« gjithĂ« ndĂ«rtimin nga — informasiya təhlĂŒkəsizliyi, sepse atĂ«herĂ« tĂ« gjithĂ« artefaktet e ndĂ«rtimit do t'i pĂ«rkasin root, dhe ndĂ«rtimi do tĂ« duhet tĂ« bĂ«het nga — informasiya təhlĂŒkəsizliyi pĂ«rsĂ«ri.

NĂ« fund, rezulton njĂ« kartĂ«, e ndarĂ« nĂ« GPT me katĂ«r pjesĂ«, ku njĂ«ra prej tyre Ă«shtĂ« FAT me uEnv.txt dhe njĂ« imazh ngarkues nĂ« formatin FIT (ai pĂ«rmban disa nĂ«nimazhe, secila me adresĂ«n e saj tĂ« ngarkimit), pjesa tjetĂ«r — e pastĂ«r, Ă«shtĂ« e supozuar tĂ« formatohet nĂ« Ext4 pĂ«r Linux. Dy pjesĂ«t tjera — misterioze: nĂ« njĂ«rin ndodhet U-Boot (sipas sa kam kuptuar, offseti i tij Ă«shtĂ« i koduar nĂ« BootROM), nĂ« tjetrĂ«n, duket se ndodhin variablat e tij tĂ« ambientit, por unĂ« pĂ«r momentin nuk i pĂ«rdor.

Niveli i parë, BootROM

Shpirti popullor thotĂ«: «NĂ«se nĂ« programim ka kĂ«rcime me bumbulla, nĂ« elektronikĂ« ka edhe me zjarĂ«fikĂ«s». Nuk Ă«shtĂ« çështja qĂ« njĂ« herĂ« isha shumĂ« afĂ«r pĂ«r tĂ« djegur bordin, duke menduar se «Epo GND Ă«shtĂ« e njĂ«jta gjĂ« si niveli i ulĂ«t» (duket, resistori do kishte ndihmuar
) Çështja Ă«shtĂ« mĂ« shumĂ« se nĂ«se duar nuk rriten nga aty, elektronika nuk ndalon sĂ« sjelluri surpriza: duke pĂ«rshkruar konektorin nĂ« bordin, nuk arrita tĂ« pĂ«rfundoj kontaktet siç duhet — nĂ« video tregojnĂ« si llak shtrihesha vetĂ« nĂ« tĂ« gjithĂ« lidhjen, vetĂ«m vendosni hekurin, por unĂ« e bĂ«ra gjithçka siç ndodhi. Ndoshta, llaku nuk ishte i pĂ«rshtatshĂ«m pĂ«r temperaturĂ«n e hekurit, ndoshta diçka tjetĂ«r
 NĂ« pĂ«rgjithĂ«si, duke parĂ« se kam mĂ« shumĂ« se njĂ« duzinĂ« kontakte, u dorĂ«zova dhe fillova tĂ« debug. Dhe kĂ«tu filloi misteri: lidh RX/TX nga UART, ngarkoj firmware — dhe atij i shkruhet

INIT
CMD0
ERROR

Epo, gjithçka Ă«shtĂ« logjike — moduli i kartĂ«s SD nuk e kam lidhur. KorrigjojmĂ« situatĂ«n, ngarkojmĂ« firmware
 Dhe heshtje
 ÇfarĂ« nuk mendoja, por kutia e vogĂ«l u hap lehtĂ«: njĂ« nga daljet e modulit duhej tĂ« ishte lidhur nĂ« VCC. NĂ« rastin tim, moduli pĂ«rkrahte 5V pĂ«r energji, kĂ«shtu qĂ«, pa menduar pĂ«r shumĂ«, vendosa telin qĂ« vinte nga moduli nĂ« anĂ«n e kundĂ«rt tĂ« bordit. Si rezultat, konektori i paqartĂ«suar doli jashtĂ« ekuilibri, dhe thjesht humbi kontakti UART. facepalm.jpg NĂ« pĂ«rgjithĂ«si, "koka e keqe nuk i jep qetĂ«si kĂ«mbĂ«ve", dhe duar tĂ« prera - kokĂ«s...

Në fund e pashë në Minicom të priturin

INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
PO loading /

Për më tepër, ndëndizësi i ngarkimit po lëviz. Menjëherë më vijnë ndërmend vitet e shkollës dhe ngarkimi i ngadaltë i MinuetOS nga disku. Të paktën disku nuk schrëqet.

Problemi është se pas mesazhit BOOT nuk ndodh asgjë. Pra, është koha për t'u lidhur përmes OpenOCD në Raspberry, të lidhim GDB në host dhe të shohim se çfarë është.

Së pari, lidhja me GDB menjëherë tregoi se $pc (program counter, adresa e instrukcionit aktual) shkon në 0x0 - ndoshta kjo ndodh pas një gabimi të shumëfishtë. Pra, menjëherë pas dënimit të mesazhit BOOT do të shtojmë një cikël të pafund. Kjo do e ndalojë për pak...

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;
 }

Ky kod i zgjuar përdoret "për qëndrueshmëri": kam dëgjuar diku se, duket, cikli i pafund është një Comportament i Padrëjtë, dhe këtu kompajleri me siguri nuk do ta kuptojë (Kujtoj se sipas 0x10000 ndodhet BootROM).

Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Duket se, çfarë tjetër të pritet - një embedded i ashpër, çfarë të bëjmë me këtu burimet. Por në atë artikull autori po e debugonte kodin në C... Kreks-feks-pex:

(gdb) file builds/zeowaa-e115/sdboot.elf
Një program po debugohet tashmë.
A jeni të sigurt që dëshironi ta ndryshoni skedarin? (y ose n) y
Duke lexuar simbolet nga builds/zeowaa-e115/sdboot.elf...kaluar.

Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Vetëm duhet ngarkuar jo skedari MIF dhe jo bin, por versionin origjinal në formatin ELF.

Tani mund të dështojmë disa herë për të gjetur adresën ku do të vazhdojë ekzekutimi (kjo është një arsye më shumë pse kompajleri nuk duhej të kuptonte se cikli ishte i pafund). Komanda

set variable $pc=0xADDR

lejon të ndryshosh vlerën e regjistrit në flakë (në këtë rast - adresën e instrukcionit aktual). Me të mund të ndryshosh vlerat e ruajtura në memorie (dhe regjistrat e hartuar me memorie).

Në fund të fundit, arrita në përfundimin (nuk jam i sigurt se është i saktë), se kemi "imazhin e kartës sd të sistemit të gabuar", dhe duhet të kalojmë jo në fillimin e të dhënave të ngarkuara, por në 0x89800 bytë më tej:

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

Ndoshta kjo është gjithashtu e lidhur me faktin që, pa patur një kartë të panevojshme 4Gb në dorë, mora një kartë 2Gb dhe duke e provuar e zëvendësova në Makefile. DEMO_END=11718750 në DEMO_END=3078900 (mos kërkoni kuptim në përkufizimin konkret - nuk ka, thjesht tani imazhi vendoset në kartë).

Niveli i dytë, U-Boot

Tani ende po «bien», por tani jemi në adresën e duhur 0x0000000080089a84. Këtu duhet të pranoj: në të vërtetë, tregimi nuk po shkon «me të gjitha ndalesat», por pjesërisht shkruhet tashmë «më vonë», prandaj këtu kam arritur të vendos skedarin e duhur dtb nga SoC ynë, duke e korrigjuar këtë në konfigurimin. HiFive_U-Boot variablin CONFIG_SYS_TEXT_BASE=0x80089800 (në vend të 0x08000000), që adresa e ngarkimit përputhet me të vërtetën. Tani ngarkojmë një kartë të nivelit të ardhshëm një tjetër imazh:

(gdb) file ..\/freedom-u-sdk\/work\/HiFive_U-Boot\/u-boot
(gdb) tui en

Dhe shohim:

   │304     
/*                                               │
   │305      * hyrja e grushtit                                    │
   │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)                      │

Për më tepër, ne kërcyem midis rreshtave 308 dhe 309. Dhe nuk është befasuese, duke pasur parasysh se në $sp ndodhet vlera 0xfffffffe31cdc0a0. Fatkeqësisht, ajo gjithashtu vazhdimisht «ikën» për shkak të rreshtit 307. Prandaj do të provojmë të vendosim një pikë ndalese në trap_entry, dhe pastaj të kthehemi përsëri në 0x80089800 (pikën e hyrjes U-Boot), dhe shpresojmë se ajo nuk kërkon vendosen e saktë të regjistrave para kalimit... Duket se funksionon:

(gdb) b trap_entry
Breakpoint 1 në 0x80089a80: skedari \/hdd\/trosinenko\/fpga\/freedom-u-sdk\/HiFive_U-Boot\/arch\/riscv\/cpu\/HiFive\/start.S, linja 308.
(gdb) vendos variablën $pc=0x80089800
(gdb) c
Duke vazhduar.

Breakpoint 1, trap_entry () në \/hdd\/trosinenko\/fpga\/freedom-u-sdk\/HiFive_U-Boot\/arch\/riscv\/cpu\/HiFive\/start.S:308
(gdb) p\/x $sp
$4 = 0x81cf950

Një tregues i tillë i grumbullit, për ta thënë, është duke treguar krejtësisht jashtë memorizimit (nëse, sigurisht, nuk kemi ende përkthimin e adresave, por të shpresojmë për variantin e thjeshtë).

Do të provojmë të zëvendësojmë treguesin në 0x881cf950. Në fund të fundit, arrijmë në atë që handle_trap thirret dhe thirret, duke u larguar në _exit_trap me argumentin epc=2148315240 (në formën decimal):

(gdb) x/10i 2148315240
   0x800cb068 :     lbu     a4,0(a5)
   0x800cb06c :     bnez    a4,0x800cb078 
   0x800cb070 :     sub     a0,a5,a0
   0x800cb074 :     ret
   0x800cb078 :     addi    a5,a5,1
   0x800cb07c :     j       0x800cb064 
   0x800cb080 : addi    sp,sp,-32
   0x800cb084 :       sd      s0,16(sp)
   0x800cb088 :       sd      ra,24(sp)
   0x800cb08c :      li      s0,0

Vëmë një pikë ndalese në strnlen, vazhdojmë dhe shohim:

(gdb) bt
#0 strnlen (s=s@entry=0x10060000 "", count=18446744073709551615) në lib/string.c:283
#1 0x00000000800cc14c në string (buf=buf@entry=0x881cbd4c "", end=end@entry=0x881cc15c "", s=0x10060000 "", field_width=, precision=, flags=) në lib/vsprintf.c:265
#2 0x00000000800cc63c në vsnprintf_internal (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=0x800d446e "s , epc x , ra lxn", fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=0x881cc1a0,
 args@entry=0x881cc188) në lib/vsprintf.c:619
#3 0x00000000800cca54 në vsnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=args@entry=0x881cc188) në lib/vsprintf.c:710
#4 0x00000000800cca68 në vscnprintf (buf=buf@entry=0x881cbd38 "exception code: 5 , ", size=size@entry=1060, fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", args=args@entry=0x881cc188) në lib/vsprintf.c:717
#5 0x00000000800ccb50 në printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn") në lib/vsprintf.c:792
#6 0x000000008008a9f0 në _exit_trap (regs=, epc=2148315240, code=) në arch/riscv/lib/interrupts.c:92
#7 handle_trap (mcause=, epc=, regs=) në arch/riscv/lib/interrupts.c:55
#8 0x0000000080089b10 në trap_entry () në /hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot/arch/riscv/cpu/HiFive/start.S:343
Backtrace stopped: frame did not save the PC

Duket se _exit_trap dëshiron të ofrojë informacionin e debugut për përjashtimin që ndodhi, por nuk po ia del. Pra, diçka sërish burimet tona nuk po shfaqen. vendos direktoriumet ..../freedom-u-sdk/HiFive_U-Boot/ O! Tani po shfaqen!

Siç duket, do ta nisim përsëri dhe do të shohim përmes shtegu të grumbullimit arsyen e problemit fillestar që shkaktoi gabimin e parë (mcause == 5). Nëse e kuptoj saktë atë që është shkruar këtu në fq. 37, kjo përjashtim do të thotë Gabimi i aksesit në ngarkim. Arsyetimi, ndoshta është këtu

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 ka atĂ« vlerĂ«n e gabuar, dhe brenda board_init_f_init_reserve ndodh gabimi. Duket se ja dhe fajtori: variabla me emrin e qartĂ« CONFIG_SYS_INIT_SP_ADDR. Ajo Ă«shtĂ« e definuar nĂ« skedarin HiFive_U-Boot/include/configs/HiFive-U540.hNĂ« njĂ« moment, mendova madje, ndoshta mund ta lĂ« mĂ« pas, duke e pĂ«rmirĂ«suar ngarkuesin pĂ«r procesorin — ndoshta Ă«shtĂ« mĂ« e lehtĂ« tĂ« rregulloj pak procesorin? Por mĂ« pas pashĂ« se kjo duket mĂ« shumĂ« si njĂ« artifact nga konfigurimi i papĂ«rfunduar pĂ«r njĂ« konfigĆ«racion tjetĂ«r memorjeje, dhe mund tĂ« provoj ta bĂ«j kĂ«shtu:#if 0-

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 */

Në një moment, numri i parregullimeve të mbajtjes teknologjike arriti një nivel kritik. Pas disa përpjekjesh, arrita në përfundimin se duhet të bëj një port korrekt për pllakën time. Për këtë duhet të kopjoj dhe rregulloj disa skedarë për konfigurimin tonë.

Pra, përafërsisht, ja pak

trosinenko@trosinenko-pc:/hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot$ git show --name-status
commit 39cd67d59c16ac87b46b51ac1fb58f16f1eb1048 (HEAD -> zeowaa-1gb)
Author: Anatoly Trosinenko 
Date:   Tue Jul 2 17:13:16 2019 +0300

    Mbështetje fillestare për pllakën Zeowaa A-E115FB

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

Detajet mund të shihen në repotitë e tij.

Si duket, nĂ« kĂ«tĂ« pllakĂ« tĂ« SiFive, regjistrat e disa pajisjeve kanĂ« adresa tĂ« tjera. Po ashtu, u zbulua se U-Boot konfigurohet me mekanizmin e njohur tĂ« Kconfig — pĂ«r shembull, mund tĂ« urdhĂ«rosh krijo menuconfig, dhe pĂ«rpara teje do tĂ« shfaqet njĂ« ndĂ«rfaqe tekstuale e pĂ«rshtatshme me pĂ«rshkrime tĂ« parametrave ? Dhe kĂ«shtu, duke bashkuar pĂ«rshkrimet e dy pllakatave pĂ«r tĂ« krijuar njĂ« pĂ«rshkrim tĂ« tretĂ«, duke hequr çdo parametĂ«r pompues tĂ« PLL (duke dukur se kjo lidhet me menaxhimin nga kompjuteri host pĂ«rmes PCIe, por nuk Ă«shtĂ« e sigurt), kam marrĂ« njĂ« firmware qĂ«, nĂ« kushte tĂ« mira nĂ« Mars, mĂ« shfaqte pĂ«rmes UART mesazhin se nga cili hash ishte ndĂ«rtuar dhe se sa DRAM kisha (por kĂ«tĂ« informacion e kisha shkruajtur vetĂ« nĂ« header).

FatkeqĂ«sisht, pas kĂ«saj, pllaka zakonisht ndalonte sĂ« pĂ«rgjigjuri pĂ«rmes JTAG tĂ« procesorit, ndĂ«rsa ngarkimi nga karta SD – njĂ« proces, fatkeqĂ«sisht, i ngadaltĂ« nĂ« konfigurimin tim. Nga ana tjetĂ«r, ndonjĂ«herĂ« BootROM jepte njĂ« mesazh qĂ« ERROR, nuk arriti tĂ« ngarkohej, dhe menjĂ«herĂ« shfaqej U-Boot. AtĂ«herĂ« e kuptova: duket se pas rinisjes bitstream nĂ« PLIS, kujtesa nuk pĂ«rditĂ«sohej, nuk arrin "tĂ« zbrazet" e kĂ«shtu me radhĂ«. NĂ« thelb, mund tĂ« lidhesha thjesht sapo shfaqej mesazhi LOADING / tĂ« lidhem me debugin dhe tĂ« jap urdhrin set variable $pc=0x80089800, duke shmangur kĂ«shtu kĂ«tĂ« ngarkim tĂ« gjatĂ« (sigurisht, me supozimin se herĂ«n e fundit dĂ«shtoi mjaft herĂ«t dhe nuk arriti tĂ« ngarkojĂ« diçka mbi kodin origjinal).

Për më tepër, a është në të vërtetë normale që procesori të ngrihet plotësisht, dhe JTAG-debugger nuk mund të lidhet me mesazhet

Gabim: e pamundur të ndalohet hart 0
Gabim:   dmcontrol=0x80000001
Gabim:   dmstatus =0x00030c82

Ndalo! KĂ«tĂ« e kam parĂ« mĂ« parĂ«! Diçka e ngjashme ndodh kur ka dhe deadlock nĂ« TileLink, dhe autori i kontrolluesit tĂ« memories nuk mĂ« beson shumĂ« – vetĂ« e kam shkruar
 Papritur, pas ndĂ«rtimit tĂ« parĂ« suksesĂ«s pas redaktimit tĂ« kontrolluesit, pashĂ«:

INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING
BOOT

U-Boot 2018.09-g39cd67d-dirty (03 Korrik 2019 - 13:50:33 +0300)

DRAM:  1 GiB
MMC:
BEFORE LOAD ENVBEFORE FDTCONTROLADDRBEFORE LOADADDRIn:    serial
Out:   serial
Err:   serial
Goditni çelësin për të ndaluar autoboot:  3

NĂ« kĂ«tĂ« rresht tĂ« çuditshĂ«m pĂ«rpara In: serial Mos iu kujtoni – kjo Ă«shtĂ« unĂ« qĂ« pĂ«rpiqesha tĂ« kuptoja nĂ« njĂ« procesor tĂ« ngadalshĂ«m nĂ«se funksionon siç duhet me ambientin. ÇfarĂ« do tĂ« thotĂ«, "PĂ«r dhjetĂ« minuta po ngec kĂ«shtu"? A Ă«shtĂ« tĂ« paktĂ«n arrirĂ« tĂ« rilokohesh dhe tĂ« kalosh nĂ« menunĂ« e ngarkimit! NjĂ« shpjegim i vogĂ«l: megjithĂ«se U-Boot ngarkon mes 2^24 bajtĂ«ve nĂ« kartĂ«n SD, sapo tĂ« niset, ai kopjon veten nĂ« njĂ« adresĂ« tjetĂ«r, ose tĂ« regjistruar nĂ« kreun e konfigurimit, ose thjesht nĂ« adresat mĂ« tĂ« larta tĂ« memories, bĂ«n rilokimin e simboleve ELF dhe i kalon atij kontrollin. Pra, duket se kaluam kĂ«tĂ« nivel dhe si bonus morĂ«m njĂ« procesor qĂ« nuk ngec pas kĂ«saj.

Pra, pse nuk funksionon timeri? Duket se orët në përgjithësi nuk ecin për ndonjë arsye


(gdb) x/x 0x0200bff8
0x200bff8:      0x00000000

ÇfarĂ«, nĂ«se e rrotullojme dorezĂ«n me dorĂ«?

(gdb) set variable *0x0200bff8=310000000
(gdb) c

Atëherë:

Shtypni ndonjë çelës për të ndaluar autoboot:  0
MMC_SPI: 0 në 0:1 hz 20000000 moda 0

Përfundimi: orët nuk ecin. Padyshim, për këtë arsye nuk funksionon as hyrja me tastierë:

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:
        /* Karakteri i parë i sekuencës ANSI 'e' */
        if (c == 'e') {
            *esc = 1;
            *key = KEY_NONE;
        }
        break;
    case 1:
        /* Karakteri i dytë i ANSI '[' */
        if (c == '[') {
...

Problemi ishte se unë paksa e teprua: unë shtova në konfigurimin e procesorit çelësin:

  case DTSTimebase => BigInt(0)


 duke u orientuar nĂ« atĂ« qĂ« nĂ« koment ishte e thĂ«nĂ« "nĂ«se nuk e dini – lĂ«reni 0". Dhe, pĂ«r mĂ« tepĂ«r, WithNBigCores nĂ« tĂ« vĂ«rtetĂ« e vendoste nĂ« 1MHz (siç ishte shprehur nĂ« konfigurimin e U-Boot). Por unĂ«, pĂ«r hir tĂ« vĂ«rtetĂ«s, isha shumĂ« i kujdesshĂ«m dhe i saktĂ«: atje nuk e di, kĂ«tu 25MHz! Si rezultat, asgjĂ« nuk funksionon. E hoqa "pĂ«rmirĂ«simet" e mia dhe...

Shtypni ndonjë çelës për të ndaluar autoboot:  0
MMC_SPI: 0 në 0:1 hz 20000000 moda 0
## Lloji i tabelës së particionit të panjohur 0
libfdt fdt_path_offset() ktheu FDT_ERR_NOTFOUND
** Asnjë tabelë particionesh - mmc 0 **
## Informacion: madhësia e të dhënave të hyrjes = 34 = 0x22
Dërgimi i uEnv.txt boot2...
## Gabim: "boot2" nuk është e definuar
HiFive-Unleashed #

Mund tĂ« futen madje edhe komandat! PĂ«r shembull, pas pak ndihmĂ«s dhe duke u pĂ«rpjekur, mund tĂ« kuptoni pĂ«rfundimisht tĂ« futni mmc_spi 1 10000000 0; mmc part, duke ulur frekuencĂ«n SPI nga 20MHz nĂ« 10MHz. Pse? Po, nĂ« konfigurim ishte shkruar frekuenca maksimale 20MHz, ajo Ă«shtĂ« aty edhe tani. Por, sa kuptova, interface-t, tĂ« paktĂ«n kĂ«tu, funksionojnĂ« kĂ«shtu: kodi ndan frekuencĂ«n e bllokut harduerik (nĂ« rastin tim — kudo 25MHz) me atĂ« tĂ« synuar, dhe vendos vlerĂ«n e marrĂ« si ndarĂ«s nĂ« regjistrin pĂ«rkatĂ«s tĂ« menaxhimit. Problemi Ă«shtĂ« se, nĂ«se pĂ«r UART-in 115200Hz do tĂ« ishte pĂ«rafĂ«rsisht ajo qĂ« nevojitet, atĂ«herĂ« nĂ«se e ndajmĂ« saktĂ«sisht 25000000 me 20000000 do tĂ« rezultojĂ« 1, dmth do tĂ« punojĂ« me 25MHz. Ndoshta, kjo Ă«shtĂ« e pranueshme, por nĂ«se vendosen kufizime, do tĂ« thotĂ« se dikujt i nevojitet (por kjo nuk Ă«shtĂ« e sigurt)
 NĂ« çdo rast, Ă«shtĂ« mĂ« e lehtĂ« tĂ« vendosĂ«sh dhe tĂ« vazhdosh — larg dhe, fatkeqĂ«sisht, pĂ«r njĂ« kohĂ« tĂ« gjatĂ«. 25MHz — kjo nuk Ă«shtĂ« njĂ« Core i9.

Të dhënat e konsolës

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

Mirë, kemi kaluar në një nivel të ri, por ende ngatërron. Ndonjëherë ndihmon dhe me eksepsione. Mund ta shohësh mcause duke pritur kodin në adresën e dhënë. $pc dhe pas si të gjendesh në trap_entry. Procesori nga U-Boot mund të shfaqë vetëm për mcause = 0..4, prandaj përgatituni të filloni nga e para në ngarkimin e pasaktë. Këtu hyra në konfigurim, e kontrollova çfarë kam ndryshuar dhe e kujtova: aty është conf/rvboot-fit.txt thuhet:

fitfile=image.fit
# më poshtë duhet të përputhet me atë që është në FIT (ugha)

ÇfarĂ«, le tĂ« sjellim tĂ« gjithĂ« skedarĂ«t nĂ« pĂ«rputhje, do ta zĂ«vendĂ«sojmĂ« komandĂ«n e kernels ndjeshĂ«m kĂ«shtu, pasi kemi dyshime se SIF0 — Ă«shtĂ« njĂ« dalje diku pĂ«rmes PCIe:

-bootargs=console=ttySIF0,921600 debug
+bootargs=console=ttyS0,125200 debug

Dhe gjithashtu do ta ndryshojmĂ« algoritmin e kriptimit nga SHA-256 nĂ« MD5: qĂ«ndrueshmĂ«ria kriptografike nuk mĂ« nevojitet (pĂ«r mĂ« tepĂ«r, gjatĂ« rregullimit), konsiderohet qĂ« Ă«shtĂ« shumĂ« e ngadalshme, dhe pĂ«r kapjen e gabimeve tĂ« integritetit gjatĂ« ngarkimit, MD5 Ă«shtĂ« mjaftueshĂ«m. ÇfarĂ« Ă«shtĂ« rezultati? Kalimi nĂ« nivelin e mĂ«parshĂ«m Ă«shtĂ« bĂ«rĂ« dukshĂ«m mĂ« i shpejtĂ« (pĂ«r shkak tĂ« kriptimit mĂ« tĂ« thjeshtĂ«), dhe u hap niveli tjetĂ«r:

...
   Verifikimi i Integritetit të Hash-it ... md5+ OK
   Ngarkimi i ngarkesave nga 0x90a5a758 në 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
chosen {
        linux,initrd-end = ;
        linux,initrd-start = ;
        riscv,kernel-end = ;
        riscv,kernel-start = ;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
libfdt fdt_path_offset() ktheu FDT_ERR_NOTFOUND
chosen {
        linux,initrd-end = ;
        linux,initrd-start = ;
        riscv,kernel-end = ;
        riscv,kernel-start = ;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
};
   Ngarkimi i Imazhit të Kernel-it ... OK
Duke ngarkuar kernelin në
3

Veçse orët nuk po bëjnë tik-tak...

(gdb) x/x 0x0200bff8
0x200bff8:      0x00000000

Ups, duket se rregullimi i orës ishte një placebo, megjithatë dukeshin se ndihmoi atëherë. Jo, duhet të riparojmë, por le të fillojmë të rrotullojmë akset manualisht dhe të shohim se çfarë ndodh:

0x00000000bff6dbb0 në ?? ()
(gdb) set variable *0x0200bff8=1000000
(gdb) c
Duke vazhduar.
^C
Programi mori sinjalin SIGINT, Ndërprerje.
0x00000000bff6dbb0 në ?? ()
(gdb) set variable *0x0200bff8=2000000
(gdb) c
Duke vazhduar.
^C
Programi mori sinjalin SIGINT, Ndërprerje.
0x00000000bff6dbb0 në ?? ()
(gdb) set variable *0x0200bff8=3000000
(gdb) c
Duke vazhduar.

Ndërkohë...

   Ngarkimi i Imazhit të Kernel-it ... OK
Duke ngarkuar kernelin në
3
2
1
0
## Duke filluar aplikacionin në 0x80000000 ...

Jo, do tĂ« shkoj tĂ« automatizoj kalimin e orĂ«ve — ndoshta ai do tĂ« pĂ«rpiqet tĂ« kalibrojĂ« timerin atje!

Dhe adresa e instruksionit aktual tani tregon diku në

0000000080001c20 :
    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 
    80001c2e:   e406                    sd      ra,8(sp)
    80001c30:   f7fff0ef                jal     ra,80001bae 
    80001c34:   8522                    mv      a0,s0
    80001c36:   267000ef                jal     ra,8000269c 
    80001c3a:   00010797                auipc   a5,0x10
    80001c3e:   41e78793                addi    a5,a5,1054 # 80012058 
    80001c42:   639c                    ld      a5,0(a5)
    80001c44:   c399                    beqz    a5,80001c4a 
    80001c46:   72c000ef                jal     ra,80002372 
    80001c4a:   45a1                    li      a1,8
    80001c4c:   4501                    li      a0,0
    80001c4e:   dc7ff0ef                jal     ra,80001a14 
    80001c52:   10500073                wfi
    80001c56:   bff5                    j       80001c52

ndĂ«r Berkeley Boot Loader. Personalish mĂ« shqetĂ«son pĂ«rmendja htif — ndĂ«rfaqja e hostit, qĂ« pĂ«rdoret pĂ«r nisjen e bashkuar tĂ« kernelit (dmth nĂ« bashkĂ«punim me hostin ARM), unĂ« mendoja se do tĂ« ishte standalone. MegjithatĂ«, nĂ«se e gjeni kĂ«tĂ« funksion nĂ« burimin, shihet se nuk Ă«shtĂ« aq keq:

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"); }
  }
}

Krijo një orë

Kërkimi për regjistrat në CLINT na çon te

    val io = IO(new Bundle {
      val rtcTick = Bool(INPUT)
    })

    val time = RegInit(UInt(0, width = timeWidth))
    when (io.rtcTick) { time := time + UInt(1) }

I cili lidhet nĂ« RTC, ose nĂ« misteriozen MockAON, pĂ«r tĂ« cilin fillimisht mendoja: «ÇfarĂ« Ă«shtĂ« kjo kĂ«tu? E paqartĂ«? E çaktivizojmĂ«!» PĂ«r shkak se ende nuk e kuptoj se çfarĂ« magjie taktike ndodh atje, prandaj thjesht do ta riprogramoj kĂ«tĂ« logjikĂ« nĂ« System.scala:

  val rtcDivider = RegInit(0.asUInt(16.W)) // për çdo rast do ta mbaj deri në 16GHz, jam optimist :)
  val mhzInt = p(DevKitFPGAFrequencyKey).toInt
  // Supozoni se frekuenca është e barabartë me një numër të plotë megahertz
  rtcDivider := Mux(rtcDivider === (mhzInt - 1).U, 0.U, rtcDivider + 1.U)
  outer.clintOpt.foreach { clint =>
    clint.module.io.rtcTick := rtcDivider === 0.U
  }

Duke kaluar te Linux kernel

Këtu tregimi tashmë është shtrirë dhe është bërë pak monoton, prandaj do ta përshkruaj sipërfaqësisht:

BBL parashikonte një FDT në adresën 0xF0000000, dhe unë e kam korrigjuar! Po mirë, do të kërkoj përsëri
 E gjeta në HiFive_U-Boot/arch/riscv/lib/boot.c, e zëvendësova me 0x81F00000, që u përcaktua në konfigurimin e nisjes së U-Boot.

Pastaj BBL ankohej se nuk kishte memorie. Rruga ime ishte nĂ« funksionin mem_prop, se nĂ« riscv-pk/machine/fdt.c: aty mĂ«sova se duhej tĂ« shĂ«nja lĂ«ndĂ«n fdt ram si device_type = "memory" — ndoshta, mĂ« vonĂ« do t'i duhet tĂ« rregulloj gjeneratorin e procesorit, por pĂ«r tani thjesht do ta shkruaj manualisht — pĂ«r çdo rast, unĂ« e kam transferuar kĂ«tĂ« skedar me dorĂ«.

Tani kam marrë një mesazh (i paraqitur në një format të strukturuar, me rikthime karte):

Kjo është bbl's dummy_payload. Për të nisur një bërthamë reale, ribëni konfigurimin e bbl
me flamurin --with-payload=PATH, pastaj rindërtoni bbl. Përndryshe,
bbl mund të përdoret në modalitetin vetëm firmware duke shtuar nyjat e pemës së pajisjeve
për një ngarkesë të jashtme dhe përdorni opsionet -bios dhe -kernel të QEMU.

Duket se janë specifikuar mundësitë siç duhet. riscv,kernel-start dhe riscv,kernel-end në DTB, por analizohen zero. Debagimi query_chosen tregon se BBL po përpiqet të analizojë një adresë 32-bitësh, ndërsa i ndodhet një çift <0x0 0xADDR>, dhe vlera e parë, duket, është bitet më të ulëta. Shtova në seksionin chosen

chosen {
      #address-cells = ;
      #size-cells = ;
      ...
}

dhe e rregullova gjenerimin e vlerave: mos shtoni 0x0 si elementin e parë.

Këto 100500 hapa të thjeshtë do të ndihmojnë lehtësisht për të parë se si bie pingvini:

Tekst i fshehur

   Verifikimi i integritetit të Hash-it ... md5+ OK
   Ngarkimi i përmbajtjeve nga 0x90a5a758 në 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
zgjedhur {
        linux,initrd-end = ;
        linux,initrd-start = ;
        riscv,kernel-end = ;
        riscv,kernel-start = ;
        #address-cells = ;
        #size-cells = ;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
        stdout-path = "uart0:38400n8";
};
libfdt fdt_path_offset() ktheu FDT_ERR_NOTFOUND
zgjedhur {
        linux,initrd-end = ;
        linux,initrd-start = ;
        riscv,kernel-end = ;
        riscv,kernel-start = ;
        #address-cells = ;
        #size-cells = ;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
        stdout-path = "uart0:38400n8";
};
   Ngarkimi i imazhit të kernelit ... OK
Startimi i kernelit në
3
2
1
0
## Duke nisur aplikacionin në 0x80000000 ...
bbl ngarkues

                SIFIVE, INC.

         5555555555555555555555555
        5555                   5555
       5555                     5555
      5555                       5555
     5555       5555555555555555555555
    5555       555555555555555555555555
   5555                             5555
  5555                               5555
 5555                                 5555
5555555555555555555555555555          55555
 55555           555555           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: Duke inekot të dhënash 0x80000000 - 0x80200000
[    0.000000] Versioni i Linux-it 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc version 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Mër 3 Korrik 21:29:21 MSK 2019
[    0.000000] bootconsole [early0] e aktivizuar
[    0.000000] Ramdisk fillestar në: 0x(____ptrval____) (16777216 bytes)
[    0.000000] Zona e rangjeve:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Fillimi i zonës së lëvizshme për çdo nyje
[    0.000000] Rangjet e hershëm të memorjes
[    0.000000]   nyja   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Setup i memorizimit të nyjës 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Në nyjën 0 totalpages: 261632
[    0.000000]   Zona DMA32: 3577 faqe përdoren për memmap
[    0.000000]   Zona DMA32: 0 faqe rezervuar
[    0.000000]   Zona DMA32: 261632 faqe, LIFO të grupeve:63
[    0.000000] TLB e softuerit IO: e mapuar [mem 0xbb1fc000-0xbf1fc000] (64MB)

(BBL shfaq emblemën, dhe ajo që ka etiketat e kohës - është bërthama).

Fatmirësisht, nuk e di si është kudo, por në RocketChip me lidhjen e debaguerit përmes JTAG, mund të kapen grushtat nga kutia - debagueri do të ndalet pikërisht në këtë pikë.

Programi mori sinjal SIGTRAP, Grushtimi / grushtimi.
0xffffffe0000024ca në ?? ()
(gdb) bt
#0  0xffffffe0000024ca në ?? ()
Grushtimi i prapambetur u ndal: çelësi i mëparshëm është identik me këtë çelës (stack i korruptuar?)
(gdb) skeda punë/linux/vmlinux
Një program është duke u debaguar tashmë.
Jeni të sigurt se doni të ndryshoni skedari? (y ose n) y
Duke lexuar simbolet nga punë/linux/vmlinux... tamam.
(gdb) bt
#0  0xffffffe0000024ca në setup_smp () në /hdd/trosinenko/fpga/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:75
#1  0x0000000000000000 në ?? ()
Grushtimi i prapambetur u ndal: çelësi nuk e ruajti PC-në

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); // < JENI JENI KET | ПРОВЕРЬбЕ, ЧбО ЭбО В ИДЕ
}

Si thoshte një anekdotë e vjetër, CPU nuk u gjet, duke punuar me emulim softueri. Apo jo duke punuar. U Humbën në një bërthamë të vetme të procesorit.

/* The lucky hart to first increment this variable will boot the other cores */
atomic_t hart_lottery;
unsigned long boot_cpu_hartid;

NjĂ« koment i mirĂ« nĂ« linux/arch/riscv/kernel/setup.c — njĂ« lloj ngjyrosjeje me metodĂ«n e Tom Sawyer. NĂ« pĂ«rgjithĂ«si, sot nuk u gjetĂ«n fitues, çmimi kalon pĂ«r edicionin e ardhshĂ«m...

Në këtë pikë, propozoj të mbyllim artikullin e zgjatur.

Vazhdimi pason. Në të do të ketë një përballje me një gabim të mençur, i cili arrin të fshihet nëse i afrohemi ngadalë nëpërmjet singlestep.

Screencast i ngarkesës (link i jashtëm):
Pjesa 3: Pothuajse po ngarkojmë Linux nga kartela SD në RocketChip

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster