Në 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 . 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:

Pamja nga poshtë:

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. .
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
makePas 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
ERROREpo, 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).

Duket se, çfarë tjetër të pritet - një embedded i ashpër, çfarë të bëjmë me këtu burimet. Por në 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.
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=0xADDRlejon 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 .rodataNdoshta 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 enDhe 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 = 0x81cf950Një 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,0Vëmë një pikë ndalese në strnlen, vazhdojmë dhe shohim:
(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=, precision=, flags=) 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 x , ra lxn", fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn", 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 x , ra lxn", 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 x , ra lxn", args=args@entry=0x881cc188) at lib/vsprintf.c:717
#5 0x00000000800ccb50 in printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc x , ra lxn") at lib/vsprintf.c:792
#6 0x000000008008a9f0 in _exit_trap (regs=, epc=2148315240, code=) at arch/riscv/lib/interrupts.c:92
#7 handle_trap (mcause=, epc=, regs=) 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 PCDuket 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 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 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.hDetajet mund të shihen në .
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 =0x00030c82Ndalo! 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: 3Në 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) cAtëherë:
Shtypni ndonjë çelës për të ndaluar autoboot: 0
MMC_SPI: 0 në 0:1 hz 20000000 moda 0Pë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 0x82000000Mirë, 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 debugDhe 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ë
3Veçse orët nuk po bëjnë tik-tak...
(gdb) x/x 0x0200bff8
0x200bff8: 0x00000000Ups, 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 80001c52ndë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):
Burimi: habr.com
