Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip В prethodni dio implementiran je više-manje radni memorijski kontroler, točnije omotač preko IP Core-a iz Quartusa, koji je adapter za TileLink. Danas ćete u odjeljku "Prenosimo RocketChip na malo poznatu kinesku ploču s Cyclone" vidjeti radnu konzolu. Proces se malo odužio: već sam mislio da ću brzo pokrenuti Linux i krenuti dalje, ali nije bilo tako. U ovom dijelu predlažem da pogledamo proces pokretanja U-Boota, BBL-a i stidljive pokušaje inicijalizacije Linux kernela. Ali postoji konzola - U-Boot, i to prilično napredna, ima mnogo toga što biste očekivali od pune konzole.

Hardver će uključivati ​​SD karticu spojenu preko SPI sučelja, kao i UART. U softverskom dijelu, BootROM će biti zamijenjen s xip na sdboot i zapravo su dodane sljedeće faze učitavanja (na SD kartici).

Dovršavanje hardvera

Dakle, zadatak: morate se prebaciti na "veliku" jezgru i spojiti UART (od Raspberry) i SD adapter (koristili smo karticu od Catalex sa šest pinova: GND, VCC, MISO, MOSI, SCK, CS) .

U principu, sve je bilo vrlo jednostavno. Ali prije nego što sam to shvatio, malo sam se bacio s jedne na drugu stranu: nakon prethodnog puta, odlučio sam da se opet samo moram umiješati System nešto kao HasPeripheryUART (i implementacija u skladu s tim), isto za SD karticu - i sve će biti spremno. Onda sam odlučio vidjeti kako je to implementirano u "ozbiljnom" dizajnu. Dakle, što je ozbiljno u vezi ovoga? Arty se, očito, ne uklapa - čudovište ostaje unleahshed.DevKitConfigs. I odjednom se pokazalo da posvuda postoje neki slojevi koji su dodani kroz parametre ključevima. Pretpostavljam da je ovo vjerojatno vrlo fleksibilno i konfigurabilno, ali volio bih barem pokrenuti nešto prvo... Zar nemate istu stvar, samo jednostavniju i dosadniju?.. Tada sam naišao vera.iofpga.FPGAChip za Microsemi FPGA i odmah ga rastavio zbog navodnika i pokušao napraviti vlastitu implementaciju po analogiji, srećom postoji više-manje cijeli "izgled matične ploče" u jednoj datoteci.

Ispostavilo se da zapravo samo trebate dodati System.scala linija

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
...

Linija u tijelu klase System dodaje informacije o frekvenciji na kojoj ovaj dio našeg SoC-a radi u dts datoteku. Koliko ja razumijem, DTS/DTB je statički analog plug-and-play tehnologije za ugrađene uređaje: stablo opisa dts kompajlira se u binarnu dtb datoteku i prenosi ga bootloader u kernel tako da može ispravno konfigurirati hardver. Zanimljivo, bez crte sa tlclock sve savršeno sintetizira, ali kompajliranje BootROM-a (dopustite da vas podsjetim, sada će to već biti sdboot) neće raditi - tijekom procesa kompilacije analizira dts datoteku i stvara zaglavlje s makronaredbom TL_CLK, zahvaljujući kojem će moći ispravno konfigurirati razdjelnike frekvencije za vanjska sučelja.

Također ćete morati malo ispraviti "ožičenje":

Platforma.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
}

Lanci registara, da budemo iskreni, dodani su jednostavno po analogiji s nekim drugim mjestima u izvornom kodu. Najvjerojatnije bi trebali zaštititi od metastabilnost. Možda u neki blokovi već imaju vlastitu zaštitu, ali prvo je želim pokrenuti barem "na visokoj razini kvalitete". Zanimljivije mi je pitanje zašto se MISO i MOSI razlikuju dq? Još nisam pronašao odgovor, ali čini se da se ostatak koda oslanja upravo na takvu vezu.

Fizički sam jednostavno dodijelio pinove dizajna slobodnim kontaktima na bloku i pomaknuo kratkospojnik za odabir napona na 3.3 V.

SD adapter

Pogled odozgo:

Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Donji pogled:

Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Otklanjanje pogrešaka softvera: Alati

Prvo, razgovarajmo o dostupnim alatima za uklanjanje pogrešaka i njihovim ograničenjima.

Minicom

Prvo, morat ćemo nekako pročitati što izlaze bootloader i kernel. Da bismo to učinili na Linuxu (u ovom slučaju na onom na RaspberryPi), potreban nam je program Minicom. Općenito govoreći, poslužit će svaki program koji radi sa serijskim priključkom.

Imajte na umu da prilikom pokretanja naziv priključnog uređaja mora biti naveden kao -D /dev/ttyS0 - nakon opcije -D. Pa, glavna informacija: za izlaz, koristite Ctrl-A, X. Zapravo sam imao slučaj kada ova kombinacija nije radila - onda možete jednostavno reći iz susjedne SSH sesije killall -KILL minicom.

Postoji još jedna značajka. Konkretno, RaspberryPi ima dva UART-a, a oba porta se već mogu za nešto prilagoditi: jedan za Bluetooth, drugi po defaultu ispisuje kernel konzolu. Srećom, ovo se ponašanje može nadjačati prema ovom priručniku.

Prepisivanje memorije

Prilikom otklanjanja pogrešaka, da bih testirao hipotezu, ponekad sam morao učitaj bootloader (oprostite) u RAM izravno s glavnog računala. Možda se to može učiniti izravno iz GDB-a, ali na kraju sam slijedio jednostavan put: kopirao sam potrebnu datoteku u Raspberry, također proslijedio port 4444 putem SSH-a (telnet iz OpenOCD-a) i upotrijebio naredbu load_image. Kada to učinite, čini se da je sve zamrznuto, ali zapravo "ne spava, samo polako trepće": Preuzima datoteku, samo to radi brzinom od nekoliko kilobajta u sekundi.

Značajke instaliranja prijelomnih točaka

Mnogi ljudi vjerojatno nisu morali razmišljati o ovome prilikom otklanjanja pogrešaka uobičajenih programa, ali prijelomne točke nisu uvijek postavljene u hardveru. Ponekad postavljanje prijelomne točke uključuje privremeno zapisivanje posebnih uputa na pravo mjesto izravno u strojni kod. Na primjer, ovako je radila moja standardna naredba b u GDB-u. Evo što slijedi:

  • ne možete staviti točku unutar BootROM-a jer ROM
  • Možete postaviti prijelomnu točku na kodu učitanom u RAM sa SD kartice, ali morate pričekati dok se ne učita. U suprotnom, nećemo prepisati dio koda, ali će učitavač prepisati našu prijelomnu točku

Siguran sam da možete izričito zatražiti korištenje hardverskih prijelomnih točaka, ali ionako ih je ograničen broj.

Brza zamjena BootROM-a

U početnoj fazi otklanjanja pogrešaka često postoji želja da se popravi BootROM i pokuša ponovno. Ali postoji problem: BootROM je dio dizajna učitanog u FPGA, a njegova sinteza je stvar nekoliko minuta (i to nakon gotovo trenutne kompilacije same BootROM slike iz C-a i Assemblera...). Srećom, u stvarnosti sve puno brže: slijed radnji je sljedeći:

  • regeneriraj bootrom.mif (prebacio sam se na MIF umjesto na HEX, jer sam uvijek imao problema s HEX-om, a MIF je Alterov izvorni format)
  • u Quartusu recimo Processing -> Update Memory Initialization File
  • na stavci Asembler (u lijevom stupcu Zadataka) naredba Start again

Sve o svemu - par desetaka sekundi.

Priprema SD kartice

Ovdje je sve relativno jednostavno, ali morate biti strpljivi i imati oko 14Gb prostora na disku:

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

Nakon čega trebate umetnuti čistu, odnosno onu koja ne sadrži ništa potrebno, SD karticu i izvršiti

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

… Gdje sdX — uređaj dodijeljen kartici. PAŽNJA: podaci na kartici bit će izbrisani, prebrisani i općenito! Teško da se isplati raditi cijelu montažu odozdo sudojer će tada svi artefakti građenja pripadati root, a montaža će se morati obaviti odozdo sudo stalno.

Rezultat je kartica označena u GPT s četiri particije, od kojih jedna ima FAT with uEnv.txt i slika za podizanje u FIT formatu (sadrži nekoliko pod-slika, svaka sa svojom adresom za preuzimanje), druga particija je prazna, trebala bi biti formatirana u Ext4 za Linux. Još dva odjeljka - tajanstvena: U-Boot živi na jednom (njegov offset je, koliko ja razumijem, hardkodiran u BootROM), na drugom, čini se, njegove varijable okoline žive, ali ja ih još ne koristim.

Prva razina, BootROM

Narodna mudrost kaže: “Ako u programiranju postoji ples s tamburicom, onda u elektronici postoji i ples s aparatom za gašenje požara.” Ne radi se čak ni o činjenici da sam jednom skoro spalio ploču, odlučivši da je "Pa, GND ista niska razina." (očigledno, otpornik ipak ne bi škodio...) Više se radi o tome da ako vam ruke ne rastu odatle, onda elektronika ne prestaje donositi iznenađenja: kod lemljenja konektora na pločicu i dalje nisam uspio dobro zalemiti kontakte - video prikazuje kako se sam lem širi preko cijelog spoja, samo primijeniti lemilo, Za mene, on je "pljusnuo" nasumce. Pa, možda lem nije bio prikladan za temperaturu lemilice, možda nešto drugo ... Općenito, kad sam vidio da već imam desetak kontakata, odustao sam i počeo ispravljati pogreške. I onda je počelo tajanstvena: Spojio sam RX/TX iz UART-a, učitavam firmware - piše

INIT
CMD0
ERROR

Pa, sve je logično - nisam spojio modul SD kartice. Ispravljamo situaciju, učitavamo firmware... I tišina... Zašto se nisam predomislio, ali mala kutija se upravo otvorila: jedan od pinova modula morao je biti spojen na VCC. U mom slučaju, modul je podržavao 5V za napajanje, pa sam bez razmišljanja priključio žicu koja dolazi iz modula na suprotnu stranu ploče. Kao rezultat toga, krivo zalemljeni konektor postao je iskrivljen i UART kontakt je jednostavno izgubljen. facepalm.jpg Općenito, "loša glava ne daje odmora nogama", a krive ruke ne daju odmora glavi...

Kao rezultat toga, vidio sam dugo očekivani

INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING /

Štoviše, pomiče se i indikator punjenja se okreće. Odmah se sjetim svojih školskih dana i ležernog učitavanja MinuetOS-a s diskete. Osim ako pogon ne melje.

Problem je što se nakon poruke BOOT ništa ne događa. To znači da je vrijeme da se preko OpenOCD-a povežete na Raspberry, na GDB na hostu i vidite što je to.

Prvo, povezivanje pomoću GDB-a je to odmah pokazalo $pc (brojač programa, adresa trenutne instrukcije) leti na 0x0 - ovo se vjerojatno događa nakon više grešaka. Stoga odmah nakon izdavanja poruke BOOT Dodajmo beskonačnu petlju. Ovo će ga odgoditi na neko vrijeme...

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

Takav lukav kod koristi se "radi pouzdanosti": Negdje sam čuo da je beskrajna petlja nedefinirano ponašanje, ali prevodilac to vjerojatno neće pogoditi (podsjećam vas da prema 0x10000 nalazi se BootROM).

Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Čini se, što drugo očekivati ​​- surovo ugrađeno, kakvi izvorni kodovi postoje? Ali u taj članak autor je ispravljao pogreške u C kodu... Kreks-fex-pex:

(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.

Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Samo trebate preuzeti ne MIF datoteku ili bin, već izvornu verziju u ELF formatu.

Sada iz n-tog pokušaja možete pogoditi adresu na kojoj će se izvođenje nastaviti (ovo je još jedan razlog zašto prevodilac nije trebao pogoditi da je petlja beskonačna). Tim

set variable $pc=0xADDR

omogućuje promjenu vrijednosti registra u hodu (u ovom slučaju, adresu trenutne instrukcije). Uz njegovu pomoć možete promijeniti vrijednosti zapisane u memoriju (i memorijsko mapirane registre).

Na kraju sam došao do zaključka (nisam siguran koji je točan) da imamo "sliku SD kartice pogrešnog sustava", te da ne moramo ići na sam početak preuzetih podataka, već na 0x89800 bajtova dalje:

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

Možda je na to utjecalo i to što sam, nemajući pri ruci nepotrebnu karticu od 4Gb, uzeo jednu od 2Gb i nasumično je zamijenio u Makefileu DEMO_END=11718750 na DEMO_END=3078900 (ne tražite značenje u određenom značenju - nema ga, samo je sada slika postavljena na karticu).

Druga razina, U-Boot

Sada još “padamo”, ali već smo na pravom mjestu 0x0000000080089a84. Ovdje moram priznati: zapravo, prezentacija ne ide "sa svim stanicama", već je djelomično napisana "nakon", tako da sam ovdje već uspio ubaciti ispravnu dtb datoteku iz našeg SoC-a, ispraviti je u postavkama HiFive_U-Boot varijabla CONFIG_SYS_TEXT_BASE=0x80089800 (umjesto 0x08000000) tako da adresa preuzimanja odgovara stvarnoj. Sada učitavamo kartu sljedeće razine, drugu sliku:

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

I vidimo:

   │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)                      │

Štoviše, skačemo između redaka 308 i 309. I nije iznenađujuće, s obzirom da u $sp leži smisao 0xfffffffe31cdc0a0. Jao, također stalno "bježi" zbog linije 307. Stoga, pokušajmo postaviti prijelomnu točku na trap_entry, a zatim se vratite na 0x80089800 (ulazna točka U-Boota), i nadajmo se da ne zahtijeva ispravno postavljanje registara prije skakanja... Čini se da radi:

(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

Pokazivač stoga je tako-tako, iskreno govoreći: pokazuje zaobilazeći RAM (osim ako, naravno, već nemamo prijevod adrese, ali nadajmo se jednostavnoj opciji).

Pokušajmo zamijeniti pokazivač sa 0x881cf950. Kao rezultat toga dolazimo do zaključka da handle_trap zvao i zvao, a istovremeno ulazimo u _exit_trap s argumentom epc=2148315240 (u decimalama):

(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

Postavite prijelomnu točku na strnlen, nastavljamo i vidimo:

(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

Izgleda kao, _exit_trap želi pružiti informacije o otklanjanju pogrešaka o iznimci koja se dogodila, ali ne može. Dakle, nekako se naši izvori opet ne prikazuju. set directories ../freedom-u-sdk/HiFive_U-Boot/ OKO! Sada prikazano!

Pa, pokrenimo ga ponovno i vidimo na praćenju stoga uzrok izvornog problema koji je uzrokovao prvu pogrešku (mcause == 5). Ako sam dobro shvatio napisano здесь na stranici 37, onda ova iznimka znači Load access fault. Čini se da je razlog ovdje

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 ima isto netočno značenje, i unutar board_init_f_init_reserve dolazi do greške. Čini se da je ovo krivac: varijabla s nedvosmislenim nazivom CONFIG_SYS_INIT_SP_ADDR. Definirano je u datoteci HiFive_U-Boot/include/configs/HiFive-U540.h. U nekom trenutku sam čak pomislio, možda, pa, trebao bih dodati boot loader za procesor - možda bi bilo lakše malo popraviti procesor? Ali onda sam vidio da je to više kao artefakt koji nije u potpunosti dovršen#if 0-specifične postavke za drugu konfiguraciju memorije, a možete pokušati učiniti ovo:

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

U nekom trenutku broj štaka tehnološki pričvršćivači dosegla kritičnu točku. Nakon malo muke, došao sam do potrebe da napravim ispravan port za svoju ploču. Da bismo to učinili, moramo kopirati i prilagoditi nekoliko datoteka kako bi odgovarale našoj konfiguraciji.

Pa, otprilike, evo male tablice

trosinenko@trosinenko-pc:/hdd/trosinenko/fpga/freedom-u-sdk/HiFive_U-Boot$ git show --name-status
commit 39cd67d59c16ac87b46b51ac1fb58f16f1eb1048 (HEAD -> zeowaa-1gb)
Author: Anatoly Trosinenko <anatoly.trosinenko@gmail.com>
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

Detalji se mogu pronaći u spremišta.

Kako se pokazalo, na ovoj SiFive ploči registri nekih uređaja imaju različite adrese. Također se pokazalo da je U-Boot konfiguriran pomoću mehanizma Kconfig, već poznatog iz jezgre Linuxa - na primjer, možete narediti make menuconfig, a pred vama će se pojaviti prikladno tekstualno sučelje s opisima parametara prema ? itd. Općenito, sastavljajući opis treće od opisa dviju ploča, izbacujući odatle sve vrste pretencioznih PLL rekonfiguracija (očigledno, to je nekako povezano s kontrolom s glavnog računala putem PCIe, ali to nije sigurno) , primio sam neki firmware, koji mi je, u pravom vremenu na Marsu, dao poruku preko UART-a o tome iz kojeg je hash-a kompajliran i o tome koliko DRAM-a imam (ali sam sam napisao ovu informaciju u zaglavlju).

Jedina šteta je što nakon toga ploča obično prestaje reagirati preko JTAG procesora, a učitavanje sa SD kartice u mojoj konfiguraciji, nažalost, nije brzo. S druge strane, ponekad je BootROM dao poruku da ERROR, nije se uspio pokrenuti, a U-Boot se odmah pojavio. Tada mi je sinulo: očito, nakon ponovnog pokretanja bitstreama u FPGA, memorija se ne briše, nema vremena za "odvježbavanje" itd. Ukratko, možete jednostavno kada se pojavi poruka LOADING / povežite se s debuggerom i naredbom set variable $pc=0x80089800, čime se zaobilazi ovo dugo učitavanje (naravno, pod pretpostavkom da se prošli put pokvario dovoljno rano da nije imao vremena učitati ništa povrh izvornog koda).

Usput, je li općenito normalno da se procesor potpuno zamrzne i da se JTAG debugger ne može spojiti s porukama na njega?

Error: unable to halt hart 0
Error:   dmcontrol=0x80000001
Error:   dmstatus =0x00030c82

Dakle, čekajte! Ovo sam već vidio! Nešto slično se događa kada je TileLink u mrtvoj blokadi, a ja nekako ne vjerujem autoru memorijskog kontrolera - sam sam to napisao... Odjednom, nakon prve uspješne ponovne izgradnje procesora nakon uređivanja kontrolera, vidio sam:

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

Ovoj čudnoj liniji prije In: serial ne obraćajte pozornost - pokušavao sam shvatiti na visećem procesoru radi li ispravno s okolinom. Kako to mislite, "Ovako visi deset minuta"? Barem se uspio premjestiti i otići na izbornik za pokretanje! Mala digresija: iako se U-Boot učitava u prva 2^24 bajta sa SD kartice, kada se pokrene, kopira se na dalju adresu, ili napisanu u zaglavlju konfiguracije, ili jednostavno na više adrese RAM-a , i izvodi ELF premještanje -karaktera, i tamo prenosi kontrolu. Dakle: izgleda da smo prošli ovu razinu i dobili bonus da procesor nakon toga nije čvrsto visio.

Pa zašto mjerač vremena ne radi? Izgleda da sat ne radi iz nekog razloga...

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

Što ako okrenete strelice ručno?

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

zatim:

Hit any key to stop autoboot:  0
MMC_SPI: 0 at 0:1 hz 20000000 mode 0

Zaključak: sat ne otkucava. Ovo je vjerojatno razlog zašto unos tipkovnicom ne radi:

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 == '[') {
...

Problem se pokazao u tome što sam bio malo prepametan: dodao sam ključ u konfiguraciju procesora:

  case DTSTimebase => BigInt(0)

... na temelju činjenice da je komentar rekao "ako ne znate, ostavite 0." I nakon svega WithNBigCores Upravo sam ga postavio na 1MHz (kao što je, usput rečeno, naznačeno u U-Boot konfiguraciji). Ali, dovraga, ja sam uredan i pedantan: tamo ne znam, ovdje je 25MHz! Na kraju ništa ne uspije. Uklonio sam svoja "poboljšanja" i...

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 #

Možete čak unositi naredbe! Na primjer, nakon malo čeprkanja, konačno možete pogoditi da uđete mmc_spi 1 10000000 0; mmc part, smanjujući SPI frekvenciju s 20MHz na 10MHz. Zašto? Pa maksimalna frekvencija od 20MHz je bila napisana u configu, i još uvijek tamo piše. Ali, koliko ja razumijem, sučelja, barem ovdje, rade ovako: kod dijeli frekvenciju hardverske jedinice (moja je posvuda 25MHz) s ciljem i postavlja dobivenu vrijednost kao djelitelj u odgovarajućoj kontroli Registar. Problem je u tome što ako za 115200Hz UART ima otprilike onoliko koliko je potrebno, onda ako podijelite 25000000 sa 20000000 dobit ćete 1, tj. radit će na 25MHz. Možda je to normalno, ali ako su postavljena ograničenja, to znači da nekome treba (ali to nije sigurno) ... Općenito, lakše je to postaviti i krenuti dalje - daleko i, nažalost, dugo. 25MHz nije Core i9.

Konzolni izlaz

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

U redu, došli smo do sljedeće razine, ali još uvijek je ledeno. A ponekad posipa i iznimkama. Možete vidjeti mcause tako što ćete čekati kod na navedenoj adresi $pc i poslije si biti na trap_entry. Sam U-Boot rukovatelj može ispisati samo za mcause = 0..4, stoga se pripremite da zapnete u netočnom pokretanju. Zatim sam ušao u konfiguraciju, počeo gledati što mijenjam i sjetio se: tamo unutra conf/rvboot-fit.txt napisano:

fitfile=image.fit
# below much match what's in FIT (ugha)

Pa, uskladimo sve datoteke, zamijenimo naredbeni redak jezgre s nečim ovakvim, budući da postoje sumnje da SIF0 - ovo je izlaz negdje preko PCIe:

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

I promijenimo algoritam raspršivanja iz SHA-256 u MD5: ne treba mi kriptografska snaga (pogotovo kod otklanjanja pogrešaka), traje užasno dugo, a za hvatanje pogrešaka integriteta tijekom učitavanja, MD5 je prelak. Koji je krajnji rezultat? Prethodnu smo razinu počeli završavati osjetno brže (zbog jednostavnijeg raspršivanja), a otvorila se sljedeća:

...
   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

Ali sat ne otkucava...

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

Ups, izgleda da se ispravljanje sata pokazalo kao placebo, iako mi se tada činilo da je pomoglo. Ne, naravno da to treba popraviti, ali prvo ručno okrenimo strelice i vidimo što će se dogoditi:

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.

U međuvremenu…

   Loading Kernel Image ... OK
Booting kernel in
3
2
1
0
## Starting application at 0x80000000 ...

Ne, idem automatizirati sat - inače će možda odlučiti tamo kalibrirati tajmer!

U međuvremenu, adresa trenutne instrukcije pokazuje negdje unutra

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>

unutar napunjenog Berkeley Boot Loadera. Osobno, ono što me zbunjuje kod ovoga je spominjanje htif — glavno sučelje koje se koristi za vezano pokretanje kernela (to jest, u suradnji s glavnim ARM-om), pretpostavio sam samostalno. Međutim, ako pronađete ovu funkciju u izvornom kodu, možete vidjeti da nije sve tako loše:

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

Potraga: pokrenite sat

Traženje registara u CLINT-u dovodi nas do

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

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

Koji se povezuje s RTC-om, odnosno s misterioznim MockAON-om, za koji sam prvo pomislio: “Pa, što mi imamo ovdje? nejasno? Ugasimo ga!" Budući da još uvijek ne razumijem kakva se to magija sata događa, pa ću samo ponovno implementirati ovu logiku u 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
  }

Probijamo se do jezgre Linuxa

Ovdje se priča već odužila i postala malo monotona, pa ću je opisati od vrha do dna:

BBL je pretpostavio prisutnost FDT-a na 0xF0000000, ali već sam to ispravio! Pa, pogledajmo ponovno... Našao sam u HiFive_U-Boot/arch/riscv/lib/boot.c, zamijenjen sa 0x81F00000, navedeno u konfiguraciji pokretanja sustava U-Boot.

Onda se BBL žalio da nema memorije. Moj put je bio u funkciji mem_prop, što u riscv-pk/stroj/fdt.c: od tamo sam naučio da trebate označiti fdt ram čvor kao device_type = "memory" - tada će možda trebati ispraviti generator procesora, ali za sada ću to samo ručno upisati - u svakom slučaju, ručno sam prenio ovu datoteku.

Sada sam dobio poruku (dostavljenu u formatiranom obliku, s povratkom na početak reda):

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.

Čini se da su opcije naznačene prema potrebi riscv,kernel-start и riscv,kernel-end u DTB, ali nule se analiziraju. Otklanjanje pogrešaka query_chosen pokazalo je da BBL pokušava analizirati 32-bitnu adresu, ali nailazi na par <0x0 0xADDR>, a čini se da su prva vrijednost najmanje značajni bitovi. Dodano u odjeljak chosen

chosen {
      #address-cells = <1>;
      #size-cells = <0>;
      ...
}

i ispravljeno generiranje vrijednosti: ne dodavati 0x0 prvi element.

Ovih 100500 XNUMX jednostavnih koraka olakšat će gledanje pada pingvina:

Skriveni tekst

   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)

(logotip prikazuje BBL, a onaj s vremenskim oznakama prikazuje kernel).

Srećom, ne znam kako je svugdje, ali na RocketChipu, kada povežete program za ispravljanje pogrešaka putem JTAG-a, možete uhvatiti zamke odmah - program za ispravljanje pogrešaka će se zaustaviti točno na ovom mjestu.

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

sloboda-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); // < ВЫ НАХОДИТЕСЬ ЗДЕСЬ
}

Kao što stari vic kaže, CPU nije pronađen, izvodi se softverska emulacija. Pa, ili ne trčanje. Izgubljen u jednoj jezgri procesora.

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

Dobar komentar u linux/arch/riscv/kernel/setup.c - vrsta slikanja ograde metodom Toma Sawyera. Općenito, iz nekog razloga danas nije bilo dobitnika, nagrada se prenosi na sljedeće izvlačenje...

Ovdje predlažem da završim ionako dugačak članak.

Nastavit će se. Uslijedit će borba s lukavom bubom koja se uspijeva sakriti ako joj se polako prikradete singlestepom.

Screencast za preuzimanje teksta (vanjska poveznica):
Dio 3: Skoro učitavanje Linuxa sa SD kartice na RocketChip

Izvor: www.habr.com

Dodajte komentar