3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде В алдыңғы бөлім азды-көпті жұмыс істейтін жад контроллері, дәлірек айтсақ, TileLink адаптері болып табылатын Quartus-тен IP Core үстінен орауыш енгізілді. Бүгін «Біз RocketChip-ті Циклонмен аз танымал қытайлық тақтаға көшіріп жатырмыз» бөлімінде сіз жұмыс істейтін консольді көресіз. Процесс біршама ұзағырақ болды: мен Linux-ты тез іске қосып, әрі қарай қозғаламын деп ойладым, бірақ олай болмады. Бұл бөлімде мен U-Boot, BBL іске қосу процесін және Linux ядросының инициализацияға деген қорқынышты әрекеттерін қарастыруды ұсынамын. Бірақ консоль бар - U-Boot және өте жетілдірілген, толыққанды консольден күтетін нәрселердің көпшілігі бар.

Аппараттық құралға SPI интерфейсі арқылы қосылған SD картасы, сондай-ақ UART кіреді. Бағдарламалық құрал бөлігінде BootROM ауыстырылады xip туралы sdboot және, шын мәнінде, келесі жүктеу кезеңдері қосылды (SD картасында).

Аппараттық құралдарды аяқтау

Сонымен, тапсырма: сізге «үлкен» ядроға ауысып, UART (таңқурайдан) және SD адаптерін қосу керек (біз Catalex-тен алты түйреуіш бар картаны қолдандық: GND, VCC, MISO, MOSI, SCK, CS) .

Негізінде бәрі өте қарапайым болды. Бірақ мұны түсінбей тұрып, мені бір жағынан екінші жаққа лақтырды: алдыңғы уақыттан кейін мен қайтадан араласу керек деп шештім. System сияқты нәрсе HasPeripheryUART (және сәйкесінше енгізу), SD картасы үшін де - және бәрі дайын болады. Содан кейін мен оның «байыпты» дизайнда қалай жүзеге асырылғанын көруді шештім. Сонымен, мұның несі маңызды? Арти, шамасы, сәйкес келмейді - құбыжық қалады unleahshed.DevKitConfigs. Кенеттен барлық жерде пернелер арқылы параметрлер арқылы қосылған қабаттасулар бар екені белгілі болды. Менің ойымша, бұл өте икемді және конфигурацияланатын шығар, бірақ мен алдымен бірдеңені іске қосқым келеді ... Сізде бірдей нәрсе бар емес пе, тек қарапайым және тітіркендіргіш?.. Сол кезде кездестім vera.iofpga.FPGAChip Microsemi FPGA үшін және оны бірден баға белгілеу үшін бөліп алып, аналогия бойынша өзімнің іске асыруды жасауға тырыстым, бақытымызға орай, бір файлда «аналық платаның орналасуы» азды-көпті бар.

Шынымен де қосу керек екен System.scala сызықтар

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

Сынып корпусындағы сызық System dts файлына SoC бұл бөлігінің жұмыс істеу жиілігі туралы ақпаратты қосады. Менің түсінуімше, DTS/DTB кірістірілген құрылғыларға арналған қосу және ойнату технологиясының статикалық аналогы болып табылады: dts сипаттау тармағы екілік dtb файлына жинақталады және жүктеуші оны дұрыс конфигурациялай алатындай етіп ядроға тасымалдайды. аппараттық құрал. Бір қызығы, сызықсыз tlclock бәрі тамаша синтезделеді, бірақ BootROM құрастыру (еске сала кетейік, енді бұл қазірдің өзінде болады sdboot) жұмыс істемейді - компиляция процесінде ол dts файлын талдайды және макроспен тақырып жасайды TL_CLK, соның арқасында ол сыртқы интерфейстер үшін жиілік бөлгіштерді дұрыс конфигурациялай алады.

Сондай-ақ, «сымдарды» аздап түзету керек:

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
}

Тіркеу тізбегі, шынын айтсам, бастапқы кодтың кейбір басқа жерлеріне ұқсастығы бойынша ғана қосылды. Сірә, олардан қорғау керек метатұрақтылық. Мүмкін ішінде некоторых блоктардың өздерінің қорғанысы бар, бірақ алдымен мен оны кем дегенде «жоғары сапалы деңгейде» іске қосқым келеді. Мен үшін қызықты сұрақ - MISO мен MOSI неге әртүрлі dq? Мен әлі жауапты таппадым, бірақ кодтың қалған бөлігі дәл осындай байланысқа негізделген сияқты.

Физикалық тұрғыдан, мен блоктағы бос контактілерге дизайн түйреуіштерін тағайындадым және кернеуді таңдау секіргішін 3.3 В-қа жылжыттым.

SD-адаптер

Жоғарғы көрініс:

3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

Төменгі көрініс:

3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

Бағдарламалық құралды жөндеу: Құралдар

Алдымен, қол жетімді жөндеу құралдары және олардың шектеулері туралы сөйлесейік.

Миником

Біріншіден, біз қандай да бір түрде жүктеуші мен ядроның не шығаратынын оқуымыз керек. Мұны Linux жүйесінде жасау үшін (бұл жағдайда RaspberryPi-де) бізге Minicom бағдарламасы қажет. Жалпы айтқанда, сериялық портпен жұмыс істейтін кез келген бағдарлама жасайды.

Іске қосу кезінде порт құрылғысының атауы ретінде көрсетілуі керек екенін ескеріңіз -D /dev/ttyS0 - опциядан кейін -D. Ал, негізгі ақпарат: шығу, пайдалану Ctrl-A, X. Менде бұл комбинация жұмыс істемейтін жағдай болды - онда сіз көрші SSH сеансынан жай ғана айта аласыз killall -KILL minicom.

Тағы бір ерекшелігі бар. Атап айтқанда, RaspberryPi-де екі UART бар және екі портты бір нәрсеге бейімдеуге болады: біреуі Bluetooth үшін, екіншісі әдепкі бойынша ядро ​​консолін шығарады. Бақытымызға орай, бұл әрекетті қайта анықтауға болады осы нұсқаулыққа сәйкес.

Жадты қайта жазу

Түзету кезінде гипотезаны тексеру үшін кейде маған тура келді жүктегішті жүктеңіз (кешіріңіз) тікелей хосттан жедел жадқа. Мүмкін, мұны тікелей GDB-ден жасауға болады, бірақ соңында мен қарапайым жолды ұстандым: мен қажетті файлды Raspberry-ге көшірдім, сонымен қатар SSH (OpenOCD-тен telnet) арқылы 4444 портын қайта жібердім және пәрменді қолдандым. load_image. Мұны істегенде, бәрі қатып қалған сияқты, бірақ шын мәнінде «Ол ұйықтамайды, жай жыпылықтайды»: Ол файлды жүктейді, оны секундына бірнеше килобайт жылдамдықпен жасайды.

Тоқтау нүктелерін орнату ерекшеліктері

Кәдімгі бағдарламаларды жөндеу кезінде көптеген адамдар бұл туралы ойлаудың қажеті жоқ шығар, бірақ тоқтау нүктелері әрқашан жабдықта орнатылмайды. Кейде тоқтау нүктесін орнату арнайы нұсқауларды қажетті жерде уақытша жазуды қамтиды тікелей машина кодына. Мысалы, менің стандартты пәрменім осылай жұмыс істеді b GDB-де. Төмендегілер:

  • BootROM ішіне нүкте қоюға болмайды, себебі ROM
  • SD картасынан ЖЖҚ жүктелген кодқа тоқтау нүктесін орнатуға болады, бірақ ол жүктелгенше күту керек. Әйтпесе, біз код бөлігін қайта жазбаймыз, бірақ жүктеуші тоқтау нүктемізді қайта жазады.

Аппараттық үзіліс нүктелерін пайдалануды сұрай алатыныңызға сенімдімін, бірақ олардың саны шектеулі.

Жылдам BootROM ауыстыру

Түзетудің бастапқы кезеңінде BootROM-ды түзетіп, әрекетті қайталау жиі болады. Бірақ мәселе бар: BootROM - бұл FPGA-ға жүктелген дизайнның бөлігі және оның синтезі бірнеше минуттық мәселе (және бұл C және Assembler-тен BootROM кескінін дереу дерлік құрастырудан кейін...). Бақытымызға орай, іс жүзінде бәрі әлдеқайда жылдам: әрекеттер тізбегі келесідей:

  • regenerate bootrom.mif (мен HEX орнына MIF-ке ауыстым, өйткені менде әрқашан HEX-те кейбір мәселелер болды, ал MIF - Alter-тің жергілікті пішімі)
  • Квартуста айтады Processing -> Update Memory Initialization File
  • Ассемблер элементінде (Тапсырмалардың сол жақ бағанында) Қайта бастау пәрмені

Барлығы туралы бәрі - бірнеше ондаған секунд.

SD картасын дайындау

Мұнда бәрі салыстырмалы түрде қарапайым, бірақ сізге шыдамдылық қажет және дискіде шамамен 14 Гб бос орын болуы керек:

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

Осыдан кейін сізге таза, дәлірек айтқанда, қажетті ештеңе жоқ SD картасын салып, оны орындау керек.

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

… Қайда sdX — картаға тағайындалған құрылғы. НАЗАР АУДАРЫҢЫЗ: картадағы деректер жойылады, қайта жазылады және жалпы! Бүкіл құрастыруды астынан жасау қиын sudoөйткені сонда барлық құрастыру артефактілері тиесілі болады root, ал құрастыруды төменнен орындау керек болады sudo үнемі.

Нәтиже - GPT-те төрт бөлімнен тұратын карта, олардың біреуінде FAT бар uEnv.txt және FIT пішіміндегі жүктелетін кескін (оның әрқайсысында жеке жүктеп алу мекенжайы бар бірнеше ішкі кескіндер бар), басқа бөлім бос, ол Linux үшін Ext4 форматында пішімделуі керек. Тағы екі бөлім - жұмбақ: U-Boot бірінде тұрады (оның офсетін, менің түсінуімше, BootROM-ға қатты кодталған), екіншісінде оның ортаның айнымалы мәндері өмір сүретін сияқты, бірақ мен оларды әлі қолданбаймын.

Бірінші деңгей, BootROM

Халық даналығы былай дейді: «Егер бағдарламалауда бубенмен билеу болса, электроникада өрт сөндіргішпен билеу де бар». Бұл тіпті бір рет «GND - бірдей төмен деңгей» деп шешіп, тақтаны өртеп жібергенім туралы емес. (шамасы, резистор зиян тигізбейтін сияқты...) Егер қолдар сол жерден өспесе, онда электроника ешқашан тосын сыйлар әкелуді тоқтатпайды: қосқышты тақтаға дәнекерлеу кезінде мен әлі де контактілерді дұрыс дәнекерлей алмадым - бейнеде дәнекерлеудің тікелей қалай таралатыны көрсетілген. бүкіл қосылым бойынша, жай ғана дәнекерлеу үтікті жағыңыз, Мен үшін ол кездейсоқ «шапалақтады». Жарайды, бәлкім, дәнекерлеу дәнекерлеуіштің температурасына сәйкес келмеді, мүмкін басқа нәрсе ... Жалпы, менде он шақты контакт бар екенін көргенде, мен бас тарттым және жөндеуге кірістім. Сосын басталды жұмбақ: Мен UART-тан RX/TX қостым, микробағдарламаны жүктеймін - дейді

INIT
CMD0
ERROR

Жақсы, бәрі қисынды - мен SD картасының модулін қосқан жоқпын. Біз жағдайды түзетеміз, микробағдарламаны жүктейміз ... Және үнсіздік ... Неліктен мен ойымды өзгерткен жоқпын, бірақ кішкене қорап жаңа ғана ашылды: модуль түйреуіштерінің бірі VCC-ге қосылуы керек еді. Менің жағдайда, модуль қуат көзі үшін 5 В қолдады, сондықтан екі рет ойланбастан, модульден келетін сымды тақтаның қарама-қарсы жағына қостым. Нәтижесінде қисық дәнекерленген қосқыш қисайған және UART байланысы жай ғана жоғалды. facepalm.jpg Жалпы, «жаман бас аяққа тыныштық бермейді», қисық қол басқа тыныштық бермейді...

Нәтижесінде мен көптен күткенді көрдім

INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING /

Оның үстіне ол қозғалады және жүктеу индикаторы айналады. Мен бірден мектептегі күндерімді және MinuetOS-ті иілгіш дискіден жай жүктеуді есіме аламын. Драйвер жарылып кетпесе.

Мәселе мынада, BOOT хабарынан кейін ештеңе болмайды. Бұл OpenOCD арқылы Raspberry-ге, хосттағы GDB-ге қосылу және оның не екенін көру уақыты келді дегенді білдіреді.

Біріншіден, GDB көмегімен қосылу бірден көрсетті $pc (бағдарлама есептегіші, ағымдағы нұсқаудың адресі) ұшады 0x0 - бұл бірнеше қателерден кейін орын алуы мүмкін. Сондықтан хабарлама шыққаннан кейін бірден BOOT Шексіз циклды қосайық. Бұл оны біраз уақытқа кешіктіреді...

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

Мұндай күрделі код «сенімділік үшін» қолданылады: мен бір жерде шексіз цикл анықталмаған мінез-құлық екенін естідім, бірақ компилятор болжауы екіталай (еске саламын: 0x10000 BootROM орналасқан).

3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

Басқа не күтуге болатын сияқты - қатал ендірілген, қандай бастапқы кодтар бар? Бірақ ішінде сол мақала автор C кодын жөндеуде... 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.

3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

Сізге MIF файлын немесе қалтасын емес, ELF пішіміндегі түпнұсқа нұсқасын жүктеп алу қажет.

Енді сіз n-ші әрекетпен орындалу жалғасатын мекен-жайды болжай аласыз (бұл компилятор циклдің шексіз екенін болжамауының тағы бір себебі). Команда

set variable $pc=0xADDR

регистр мәнін жылдам өзгертуге мүмкіндік береді (бұл жағдайда ағымдағы нұсқаудың адресі). Оның көмегімен жадқа жазылған мәндерді (және жадымен салыстырылған регистрлерді) өзгертуге болады.

Сайып келгенде, мен (қайсысы дұрыс екенін білмеймін) бізде «қате жүйенің SD картасының кескіні» бар деген қорытындыға келдім және біз жүктелген деректердің ең басына емес, 0x89800 байт ары қарай:

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

Қолымда қажетсіз 4 Гб картасы болмағандықтан, мен 2 Гб картасын алып, оны Makefile файлына кездейсоқ ауыстырғаным да әсер еткен шығар. DEMO_END=11718750 туралы DEMO_END=3078900 (белгілі бір мағынада мағынаны іздемеңіз - жоқ, қазір сурет картаға орналастырылған).

Екінші деңгей, U-Boot

Қазір біз әлі де «құлап жатырмыз», бірақ біз дұрыс жердеміз 0x0000000080089a84. Мен мойындауым керек: іс жүзінде презентация «барлық аялдамалармен» жүрмейді, бірақ ішінара «кейін» деп жазылған, сондықтан мен мұнда біздің SoC-тен дұрыс dtb файлын енгізіп үлгердім, оны параметрлерде түзетіңіз. HiFive_U-Boot айнымалы CONFIG_SYS_TEXT_BASE=0x80089800 (орнына 0x08000000) жүктеп алу мекенжайы нақты мекенжайға сәйкес болуы үшін. Енді біз келесі деңгейдің картасын жүктейміз, басқа сурет:

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

Және біз көреміз:

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

Сонымен қатар, біз 308 және 309 жолдар арасында секіреміз. Және бұл таңқаларлық емес, бұл $sp мағынасы жатыр 0xfffffffe31cdc0a0. Өкінішке орай, ол 307 жолға байланысты үнемі «қашып кетеді». Сондықтан тоқтау нүктесін орнатуға тырысайық. trap_entry, содан кейін қайтып оралыңыз 0x80089800 (U-Boot кіру нүктесі) және секіру алдында регистрлердің дұрыс орнатылуын талап етпейді деп үміттенейік... Ол жұмыс істейтін сияқты:

(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

Стек көрсеткіші солай, шынын айтқанда: ол ЖЖҚ-ны толығымен айналып өтуді көрсетеді (егер, әрине, бізде мекенжай аудармасы жоқ болса, бірақ қарапайым нұсқаға үміттенейік).

Көрсеткішті ауыстырып көрейік 0x881cf950. Нәтижесінде біз мынадай қорытындыға келеміз handle_trap қоңырау шалып, қоңырау шалдық, сонымен бірге біз кіреміз _exit_trap дәлелмен epc=2148315240 (ондықпен):

(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

Тоқтау нүктесін орнатыңыз strnlen, біз жалғастырамыз және көреміз:

(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

Болуы мүмкін, _exit_trap орын алған ерекшелік туралы түзету ақпаратын бергісі келеді, бірақ ол алмайды. Сонымен, әйтеуір біздің дереккөздер қайтадан көрсетілмейді. set directories ../freedom-u-sdk/HiFive_U-Boot/ ТУРАЛЫ! Енді көрсетілді!

Енді оны қайтадан іске қосып, стектен бірінші қатені тудырған бастапқы мәселенің себебін көрейік (mcause == 5). Жазылғанын дұрыс түсінсем осында 37-бетте, онда бұл ерекшелік білдіреді Load access fault. Мұның себебі осында болған сияқты

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 бірдей дұрыс емес мағынасы бар және ішінде board_init_f_init_reserve қате орын алады. Бұл кінәлі сияқты: бір мағыналы аты бар айнымалы CONFIG_SYS_INIT_SP_ADDR. Ол файлда анықталған HiFive_U-Boot/include/configs/HiFive-U540.h. Бір кезде мен тіпті ойладым, мүмкін, процессорға жүктеуші қосу керек - мүмкін процессорды сәл жөндеу оңайырақ болар ма еді? Бірақ кейін мен оның толық аяқталмаған артефакт сияқты екенін көрдім#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 */

Бір сәтте балдақтардың саны технологиялық бекіткіштер сыни нүктеге жетті. Біраз күрескеннен кейін мен тақтаға дұрыс порт жасау қажеттілігіне келдім. Ол үшін біз конфигурациямызға сәйкес бірнеше файлдарды көшіріп, реттеуіміз керек.

Міне, шамалы үстел

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

Толық ақпаратты мына жерден табуға болады репозиторийлер.

Белгілі болғандай, бұл SiFive тақтасында кейбір құрылғылардың регистрлерінің адрестері әртүрлі. Сондай-ақ, U-Boot Linux ядросынан бұрыннан таныс Kconfig механизмі арқылы конфигурацияланғаны белгілі болды - мысалы, сіз пәрмен бере аласыз. make menuconfig, ал параметрлердің сипаттамаларын көрсететін ыңғайлы мәтіндік интерфейс пайда болады ? т.б. Тұтастай алғанда, екі тақтаның сипаттамасынан үшіншісінің сипаттамасын біріктіріп, сол жерден барлық түрдегі PLL қайта конфигурацияларын алып тастаңыз (шамасы, бұл PCIe арқылы негізгі компьютерден басқаруға байланысты, бірақ бұл анық емес) , Мен кейбір микробағдарламаны алдым, ол Марста дұрыс ауа-райында маған UART арқылы оның қай миссия хэшінен құрастырылғаны және менде қанша DRAM бар екендігі туралы хабарлама берді (бірақ бұл ақпаратты тақырыпта өзім жаздым).

Жалғыз өкініштісі, осыдан кейін тақта әдетте JTAG процессоры арқылы жауап беруді тоқтатты және SD картасынан жүктеу, өкінішке орай, менің конфигурациямда жылдам емес. Екінші жағынан, кейде BootROM бұл туралы хабарлама берді ERROR, жүктелмеді және U-Boot бірден пайда болды. Дәл сол кезде маған таң қалды: биттік ағынды FPGA-ға қайта жүктегеннен кейін жад өшірілмейді, оның «үйретуге» уақыты жоқ және т.б. Қысқасы, сіз хабарлама пайда болған кезде ғана жасай аласыз LOADING / отладчикпен және пәрменмен қосылыңыз set variable $pc=0x80089800, осылайша бұл ұзақ жүктеуді айналып өту (әрине, соңғы рет ол ертерек бұзылып, бастапқы кодтың үстіне ештеңе жүктеп үлгермеді деген болжам бойынша).

Айтпақшы, процессордың толығымен қатып қалуы және хабарламалары бар JTAG отладчик оған қосыла алмайтыны қалыпты жағдай ма?

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

Сонымен, күтіңіз! Мен мұны әлдеқашан көрдім! TileLink тығырыққа тірелген кезде ұқсас нәрсе болады және мен жад контроллерінің авторына қандай да бір түрде сенбеймін - мен оны өзім жаздым ... Кенеттен, контроллерді өңдегеннен кейін процессорды бірінші сәтті қайта құрудан кейін мен мынаны көрдім:

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

Бұрын бұл оғаш сызыққа In: serial назар аудармаңыз - мен ілулі процессордың қоршаған ортамен дұрыс жұмыс істейтінін түсінуге тырыстым. «Он минут бойы осылай ілулі тұрды» дегенді қалай түсінесіңдер? Кем дегенде, ол орын ауыстырып, жүктеу мәзіріне кірді! Шағын ауытқу: U-Boot SD картасынан алғашқы 2^24 байтта жүктелсе де, ол іске қосылғанда, ол конфигурация тақырыбына жазылған алысырақ мекенжайға немесе жай ғана жоғарырақ мекенжайларға көшіреді. RAM, және ELF орнын ауыстыруды орындайды -таңбалар, және сол жерде басқаруды береді. Сонымен: біз осы деңгейден өттік және процессор одан кейін мықтап ілінбеген бонус алған сияқтымыз.

Сонымен, таймер неге жұмыс істемейді? Сағат қандай да бір себептермен жұмыс істемей тұрған сияқты...

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

Көрсеткілерді қолмен бұрсаңыз ше?

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

Сонда:

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

Қорытынды: сағат жұмыс істемейді. Сондықтан пернетақтадан енгізу жұмыс істемейді:

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

Мәселе менің тым ақылды болғанымда болды: процессор конфигурациясына кілтті қостым:

  case DTSTimebase => BigInt(0)

... түсініктемеде «егер білмесеңіз, 0 қалдырыңыз» деп жазылғанына негізделген. Ақыр соңында WithNBigCores Мен оны жай ғана 1МГц-ке қойдым (айтпақшы, ол U-Boot конфигурациясында көрсетілген). Бірақ, мен ұқыптымын және ұқыптымын: мен оны білмеймін, мұнда 25 МГц! Ақырында ештеңе жұмыс істемейді. Мен «жақсартуларымды» алып тастадым және...

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 #

Сіз тіпті командаларды енгізе аласыз! Мысалы, аздап үңілгеннен кейін, сіз кіруді болжауға болады mmc_spi 1 10000000 0; mmc part, SPI жиілігін 20МГц-тен 10МГц-ке дейін азайту. Неліктен? 20 МГц максималды жиілігі конфигурацияда жазылған және ол әлі де сол жерде жазылған. Бірақ, менің түсінуімше, интерфейстер, кем дегенде, мұнда жұмыс істейді: код аппараттық блоктың жиілігін (менікі барлық жерде 25 МГц) мақсатқа бөледі және алынған мәнді тиісті басқару элементінде бөлгіш ретінде орнатады. тіркелу. Мәселе мынада, егер 115200 Гц UART үшін шамамен не қажет болса, онда 25000000-ды 20000000-ға бөлсеңіз, сіз 1 аласыз, яғни. ол 25 МГц жиілікте жұмыс істейді. Мүмкін, бұл қалыпты жағдай, бірақ егер шектеулер қойылса, бұл біреуге қажет екенін білдіреді (бірақ бұл нақты емес) ... Жалпы алғанда, оны орнату және алға жылжу оңайырақ - алыс және, өкінішке орай, ұзақ уақытқа. 25 МГц Core i9 емес.

Консоль шығысы

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

Жарайды, біз келесі деңгейге жеттік, бірақ ол әлі де қатып тұр. Кейде ол ерекше жағдайларды да шашады. Көрсетілген мекенжайда кодты күту арқылы сіз оны көре аласыз $pc және кейін si қосулы болыңыз trap_entry. U-Boot өңдегішінің өзі тек mcause = 0..4 үшін ғана шығара алады, сондықтан қате жүктеуде тұрып қалуға дайын болыңыз. Содан кейін мен конфигурацияға кіріп, нені өзгерткенімді қарай бастадым және есіме түсті: сонда conf/rvboot-fit.txt жазылған:

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

Келіңіздер, барлық файлдарды сәйкестендіруге рұқсат етіңіз, ядро ​​​​пәрмен жолын осындай нәрсемен ауыстырыңыз, өйткені күдік бар. SIF0 - бұл PCIe арқылы бір жерден шыққан шығыс:

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

Және хэштеу алгоритмін SHA-256-дан MD5-ке өзгертейік: маған криптографиялық күш қажет емес (әсіресе жөндеу кезінде), бұл өте көп уақытты алады және жүктеу кезінде тұтастық қателерін анықтау үшін MD5 тым оңай. Ақырғы нәтиже қандай? Біз алдыңғы деңгейді тезірек аяқтай бастадық (қарапайым хэшингке байланысты), ал келесісі ашылды:

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

Бірақ сағат жүрмейді...

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

Ой, сағатты түзету плацебо болып шыққан сияқты, бірақ ол кезде маған көмектесті. Жоқ, әрине, оны түзету керек, бірақ алдымен көрсеткілерді қолмен бұрып, не болатынын көрейік:

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.

Бұл арада...

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

Жоқ, мен сағатты автоматтандыруға барамын - әйтпесе ол таймерді сол жерде калибрлеуді шешер!

Осы уақытта ағымдағы нұсқаулықтың мекенжайы бір жерде көрсетіледі

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>

жүктелген Беркли жүктегішінің ішінде. Жеке мені бұл туралы шатастыратын нәрсе - бұл ескерту htif — ядроны байланыстырылған іске қосу үшін пайдаланылатын хост интерфейсі (яғни ARM хостымен ынтымақтастықта), мен автономды деп есептедім. Дегенмен, егер сіз бұл функцияны бастапқы кодта тапсаңыз, бәрі соншалықты жаман емес екенін көре аласыз:

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

Тапсырма: сағатты бастаңыз

CLINT-те регистрлерді іздеу бізді келесіге әкеледі

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

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

Қайсысы RTC-ге немесе жұмбақ MockAON-ға қосылады, ол туралы мен бастапқыда ойладым: «Сонымен, бізде не бар? Түсінікті емес пе? Өшірейік!» Мен ол жерде қандай сағат сиқыры болып жатқанын әлі түсінбегендіктен, мен бұл логиканы қайта енгіземін. 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
  }

Linux ядросына барамыз

Мұнда әңгіме созылып кетті және аздап монотонды болды, сондықтан мен оны жоғарыдан төменге дейін сипаттаймын:

BBL FDT бар деп есептеді 0xF0000000, бірақ мен оны түзетіп қойдым! Жарайды, тағы қарайық... Ішінде таптым HiFive_U-Boot/arch/riscv/lib/boot.c, ауыстырылады 0x81F00000, U-Boot жүктеу конфигурациясында көрсетілген.

Содан кейін BBL жады жоқ деп шағымданды. Менің жолым функцияда болды mem_propсол riscv-pk/machine/fdt.c: сонда мен fdt ram түйінін белгілеу керек екенін білдім device_type = "memory" - содан кейін процессор генераторын түзету қажет болуы мүмкін, бірақ мен оны қолмен жазамын - бәрібір, мен бұл файлды қолмен жібердім.

Енді мен хабарламаны алдым (пішімделген пішінде берілген, кареткамен қайтарылған):

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.

Қажетті нұсқалар көрсетілген сияқты riscv,kernel-start и riscv,kernel-end DTB-де, бірақ нөлдер талданады. Түзету query_chosen BBL 32-биттік мекенжайды талдауға тырысатынын көрсетті, бірақ ол жұпқа тап болады <0x0 0xADDR>, және бірінші мән ең аз маңызды бит болып көрінеді. Бөлімге қосылды chosen

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

және мәндерді генерациялау түзетілді: қоспаңыз 0x0 бірінші элемент.

Бұл 100500 XNUMX қарапайым қадам пингвиннің құлауын бақылауды жеңілдетеді:

Жасырын мәтін

   Verifying Hash Integrity ... md5+ OK
   Loading loadables from 0x90a5a758 to 0x82000000
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
chosen {
        linux,initrd-end = <0x83000000>;
        linux,initrd-start = <0x82000000>;
        riscv,kernel-end = <0x80a00000>;
        riscv,kernel-start = <0x80200000>;
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
        stdout-path = "uart0:38400n8";
};
libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND
chosen {
        linux,initrd-end = <0x83000000>;
        linux,initrd-start = <0x82000000>;
        riscv,kernel-end = <0x80a00000>;
        riscv,kernel-start = <0x80200000>;
        #address-cells = <0x00000001>;
        #size-cells = <0x00000000>;
        bootargs = "debug console=tty0 console=ttyS0,125200 root=/dev/mmcblk0p2 rootwait";
        stdout-path = "uart0:38400n8";
};
   Loading Kernel Image ... OK
Booting kernel in
3
2
1
0
## Starting application at 0x80000000 ...
bbl loader

                SIFIVE, INC.

         5555555555555555555555555
        5555                   5555
       5555                     5555
      5555                       5555
     5555       5555555555555555555555
    5555       555555555555555555555555
   5555                             5555
  5555                               5555
 5555                                 5555
5555555555555555555555555555          55555
 55555           555555555           55555
   55555           55555           55555
     55555           5           55555
       55555                   55555
         55555               55555
           55555           55555
             55555       55555
               55555   55555
                 555555555
                   55555
                     5

           SiFive RISC-V Core IP
[    0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[    0.000000] Linux version 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc version 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Wed Jul 3 21:29:21 MSK 2019
[    0.000000] bootconsole [early0] enabled
[    0.000000] Initial ramdisk at: 0x(____ptrval____) (16777216 bytes)
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] On node 0 totalpages: 261632
[    0.000000]   DMA32 zone: 3577 pages used for memmap
[    0.000000]   DMA32 zone: 0 pages reserved
[    0.000000]   DMA32 zone: 261632 pages, LIFO batch:63
[    0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)

(логотип BBL арқылы көрсетіледі, ал уақыт белгілері бар ядро ​​арқылы көрсетіледі).

Бақытымызға орай, мен оның барлық жерде қалай екенін білмеймін, бірақ RocketChip-те қате түзеткішті JTAG арқылы қосқанда, қораптың сыртындағы тұзақтарды ұстауға болады - отладчик дәл осы сәтте тоқтайды.

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

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

Ескі әзіл айтқандай, CPU табылмады, бағдарламалық жасақтама эмуляциясы іске қосылған. Жақсы, немесе жүгірмеу. Бір процессор өзегінде жоғалған.

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

Керемет пікір linux/arch/riscv/kernel/setup.c - Том Сойер әдісімен қоршауды бояудың бір түрі. Жалпы бүгін қандай да бір себептермен жеңімпаздар табылмады, жүлде келесі ұтыс ойынына ауыстырылды...

Міне, мен қазірдің өзінде ұзақ мақаланы аяқтауды ұсынамын.

Жалғастыру. Жалғыз қадаммен ақырын басып өтсеңіз, жасырынатын айлакер қателікпен күрес болады.

Мәтінді жүктеу скринкаст (сыртқы сілтеме):
3-бөлім: Linux SD картасынан RocketChip-ге дерлік жүктелуде

Ақпарат көзі: www.habr.com

пікір қалдыру