3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda В oldingi qism ko'proq yoki kamroq ishlaydigan xotira kontrolleri, to'g'rirog'i, TileLink uchun adapter bo'lgan Quartus-dan IP Core ustidan o'rash amalga oshirildi. Bugun "Biz RocketChip-ni Cyclone bilan kam taniqli Xitoy platasiga o'tkazmoqdamiz" bo'limida siz ishlaydigan konsolni ko'rasiz. Jarayon biroz ko'proq vaqt talab qildi: men allaqachon Linuxni tezda ishga tushiraman va davom etaman deb o'ylagandim, lekin unday emas edi. Ushbu qismda men U-Boot, BBL-ni ishga tushirish jarayonini va Linux yadrosining ishga tushirish uchun qo'rqoq urinishlarini ko'rib chiqishni taklif qilaman. Ammo konsol mavjud - U-Boot va ancha rivojlangan, to'liq huquqli konsoldan siz kutgan narsaga ega.

Uskunaga SPI interfeysi orqali ulangan SD-karta, shuningdek, UART kiradi. Dasturiy ta'minot qismida BootROM bilan almashtiriladi xip haqida sdboot va, aslida, quyidagi yuklash bosqichlari qo'shilgan (SD-kartada).

Uskunani tugatish

Shunday qilib, vazifa: siz "katta" yadroga o'tishingiz va UART (Raspberry-dan) va SD adapterini ulashingiz kerak (biz Catalex-dan oltita pinli kartadan foydalandik: GND, VCC, MISO, MOSI, SCK, CS) .

Aslida, hamma narsa juda oddiy edi. Ammo buni anglamasdan oldin, men u yoqdan-bu yoqqa otildim: oldingi vaqtdan keyin men yana aralashishim kerak deb qaror qildim. System shunga o'xshash narsa HasPeripheryUART (va shunga mos ravishda amalga oshirish), SD-karta uchun ham xuddi shunday - va hamma narsa tayyor bo'ladi. Keyin men "jiddiy" dizaynda qanday amalga oshirilganligini ko'rishga qaror qildim. Xo'sh, buning nimasi jiddiy? Arti, aftidan, mos kelmaydi - yirtqich hayvon qoladi unleahshed.DevKitConfigs. Va to'satdan hamma joyda parametrlar orqali kalitlar orqali qo'shilgan ba'zi qoplamalar borligi ma'lum bo'ldi. O'ylaymanki, bu juda moslashuvchan va sozlanishi mumkin, lekin men hech bo'lmaganda avval biror narsani ishga tushirishni xohlayman ... Sizda ham xuddi shunday, oddiyroq va zerikarliroq emasmi?.. O‘shanda men duch keldim vera.iofpga.FPGAChip Microsemi FPGA-lar uchun va darhol uni qo'shtirnoq uchun ajratib oldim va o'xshatish bo'yicha o'zimni amalga oshirishga harakat qildim, xayriyatki, bitta faylda ko'proq yoki kamroq "ana plata tartibi" mavjud.

Siz haqiqatan ham qo'shishingiz kerakligi ma'lum bo'ldi System.scala chiziqlar

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

Sinf tanasidagi chiziq System dts fayliga SoC ning ushbu qismi ishlash chastotasi haqida ma'lumot qo'shadi. Men tushunganimdek, DTS/DTB o'rnatilgan qurilmalar uchun plagin va o'ynatish texnologiyasining statik analogidir: dts tavsifi daraxti ikkilik dtb fayliga kompilyatsiya qilinadi va yuklovchi tomonidan yadroga uzatiladi, shunda u to'g'ri sozlashi mumkin. apparat. Qizig'i shundaki, bilan chiziqsiz tlclock hamma narsa mukammal sintezlanadi, lekin BootROM-ni kompilyatsiya qilish (eslatmaga ruxsat beraman, endi bu allaqachon bo'ladi sdboot) ishlamaydi - kompilyatsiya jarayonida u dts faylini tahlil qiladi va makros bilan sarlavha yaratadi. TL_CLK, buning yordamida u tashqi interfeyslar uchun chastota ajratgichlarni to'g'ri sozlashi mumkin.

Shuningdek, siz "simlarni" biroz tuzatishingiz kerak bo'ladi:

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
}

Ro'yxatga olish zanjirlari, rostini aytsam, asl koddagi boshqa joylarga o'xshash tarzda qo'shilgan. Katta ehtimol bilan ular himoya qilishlari kerak metastabillik. Balki ichida biroz bloklar allaqachon o'z himoyasiga ega, lekin birinchi navbatda men uni hech bo'lmaganda "yuqori sifat darajasida" ishga tushirmoqchiman. Men uchun qiziqroq savol nima uchun MISO va MOSI bir-biridan farq qiladi dq? Men javobni hali topa olmadim, lekin kodning qolgan qismi aynan shunday aloqaga tayanganga o'xshaydi.

Jismoniy jihatdan, men oddiygina dizayn pinlarini blokdagi bo'sh kontaktlarga tayinladim va kuchlanishni tanlash o'tish moslamasini 3.3V ga o'tkazdim.

SD adapter

Yuqoridan ko'rinish:

3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

Pastki ko'rinish:

3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

Dasturiy ta'minotni tuzatish: asboblar

Birinchidan, mavjud disk raskadrovka vositalari va ularning cheklovlari haqida gapiraylik.

Minikom

Birinchidan, biz qandaydir tarzda bootloader va yadro chiqishini o'qishimiz kerak. Buni Linuxda qilish uchun (bu holda, RaspberryPi-da) bizga Minicom dasturi kerak. Umuman olganda, ketma-ket port bilan ishlaydigan har qanday dastur ishlaydi.

Shuni esda tutingki, ishga tushirishda port qurilma nomi sifatida ko'rsatilishi kerak -D /dev/ttyS0 - variantdan keyin -D. Xo'sh, asosiy ma'lumot: chiqish, foydalanish Ctrl-A, X. Menda bu kombinatsiya ishlamagan holat bo'lgan - keyin siz shunchaki qo'shni SSH sessiyasidan aytishingiz mumkin killall -KILL minicom.

Yana bitta xususiyat bor. Xususan, RaspberryPi ikkita UARTga ega va ikkala port ham biror narsaga moslashtirilishi mumkin: biri Bluetooth uchun, ikkinchisi sukut bo'yicha yadro konsolini chiqaradi. Yaxshiyamki, bu xatti-harakatni bekor qilish mumkin ushbu qo'llanmaga muvofiq.

Xotirani qayta yozish

Nosozliklarni tuzatishda, gipotezani sinab ko'rish uchun men ba'zan majbur bo'ldim yuklash vositasini yuklang (kechirasiz) to'g'ridan-to'g'ri xostdan RAMga. Ehtimol, buni to'g'ridan-to'g'ri GDB-dan qilish mumkin, lekin oxirida men oddiy yo'lni tutdim: men kerakli faylni Raspberry-ga ko'chirdim, shuningdek, SSH (OpenOCD-dan telnet) orqali 4444-portni yo'naltirdim va buyruqni ishlatdim. load_image. Buni qilganingizda, hamma narsa muzlatilganga o'xshaydi, lekin aslida "U uxlamaydi, sekin miltillaydi": U faylni yuklab oladi, u buni soniyasiga bir necha kilobayt tezlikda bajaradi.

To'xtash nuqtalarini o'rnatish xususiyatlari

Ko'p odamlar, ehtimol, muntazam dasturlarni disk raskadrovka qilishda bu haqda o'ylamagan bo'lishi mumkin, ammo to'xtash nuqtalari har doim ham apparatda o'rnatilmaydi. Ba'zan to'xtash nuqtasini o'rnatish maxsus ko'rsatmalarni to'g'ri joyda vaqtincha yozishni o'z ichiga oladi to'g'ridan-to'g'ri mashina kodiga. Misol uchun, mening standart buyrug'im shunday ishlagan b GDBda. Quyidagilar:

  • BootROM ichiga nuqta qo'ya olmaysiz, chunki ROM
  • SD-kartadan RAMga yuklangan kodda to'xtash nuqtasini o'rnatishingiz mumkin, lekin u yuklanmaguncha kutishingiz kerak. Aks holda, biz kod qismini qayta yozmaymiz, lekin yuklovchi bizning to'xtash nuqtamizni qayta yozadi.

Ishonchim komilki, siz aniq apparat uzilish nuqtalaridan foydalanishni so'rashingiz mumkin, ammo baribir ularning soni cheklangan.

BootROMni tez almashtirish

Nosozliklarni tuzatishning dastlabki bosqichida ko'pincha BootROM-ni tuzatish va qayta urinib ko'rish istagi paydo bo'ladi. Ammo muammo bor: BootROM FPGA-ga yuklangan dizaynning bir qismidir va uning sintezi bir necha daqiqa vaqtni oladi (va bu C va Assembler-dan BootROM tasvirining o'zi deyarli bir zumda kompilyatsiya qilinganidan keyin...). Yaxshiyamki, aslida hamma narsa ancha tezroq: harakatlar ketma-ketligi quyidagicha:

  • regenerate bootrom.mif (men HEX o'rniga MIFga o'tdim, chunki men har doim HEX bilan ba'zi muammolarga duch kelganman va MIF Alterning mahalliy formati)
  • Kvartda deyishadi Processing -> Update Memory Initialization File
  • Assembler elementida (Vazifalarning chap ustunida) Qayta boshlash buyrug'i

Hamma narsa haqida - bir necha o'n soniya.

SD karta tayyorlanmoqda

Bu erda hamma narsa nisbatan sodda, lekin siz sabrli bo'lishingiz va taxminan 14 Gb disk maydoniga ega bo'lishingiz kerak:

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

Shundan so'ng siz toza, to'g'rirog'i, hech qanday zarur bo'lmagan SD-kartani kiritishingiz va uni bajarishingiz kerak.

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

… Qayerda sdX — kartaga tayinlangan qurilma. DIQQAT: kartadagi ma'lumotlar o'chiriladi, ustiga yoziladi va umuman olganda! Butun montajni pastdan bajarish qiyin sudochunki u holda barcha qurilish artefaktlari tegishli bo'ladi root, va montajni pastdan bajarish kerak bo'ladi sudo doimiy.

Natijada GPT-da to'rtta bo'limga ega bo'lgan karta paydo bo'ladi, ulardan birida FAT mavjud uEnv.txt va FIT formatidagi yuklanadigan tasvir (uning har biri o'z yuklab olish manziliga ega bo'lgan bir nechta pastki rasmlarni o'z ichiga oladi), boshqa bo'lim bo'sh, u Linux uchun Ext4 formatida formatlangan bo'lishi kerak. Yana ikkita bo'lim - sirli: U-Boot birida yashaydi (uning ofseti, men tushunganimdek, BootROM-ga qattiq kodlangan), boshqa tomondan, uning muhit o'zgaruvchilari yashaydi, lekin men ulardan hali foydalanmayapman.

Birinchi daraja, BootROM

Xalq donoligida shunday deyilgan: "Agar dasturlashda daf bilan raqs tushsa, elektronikada ham o't o'chirgich bilan raqs tushadi." Bu hatto bir marta men "Yaxshi, GND bir xil past daraja" deb qaror qilib, taxtani deyarli yoqib yuborganim haqida emas. (Aftidan, rezistor zarar ko'rmaydi ...) Bu ko'proq, agar qo'llar u erdan o'smasa, elektronika hech qachon kutilmagan hodisalar keltirishni to'xtatmaydi: ulagichni taxtaga lehimlashda men hali ham kontaktlarni to'g'ri lehimlay olmadim - videoda lehimning to'g'ridan-to'g'ri qanday tarqalishi ko'rsatilgan. butun ulanish bo'ylab, shunchaki lehim temirini qo'llang, men uchun u tasodifan "tarsa" tashladi. Xo'sh, ehtimol, lehim lehimli temirning haroratiga mos kelmadi, ehtimol boshqa narsa ... Umuman olganda, men allaqachon o'nlab kontaktlarim borligini ko'rganimda, men voz kechdim va disk raskadrovka qilishni boshladim. Va keyin boshlandi sirli: UART dan RX/TX ni uladim, proshivkani yukladim - deydi

INIT
CMD0
ERROR

Xo'sh, hamma narsa mantiqiy - men SD-karta modulini ulamadim. Biz vaziyatni to'g'irlaymiz, proshivkani yuklaymiz ... Va sukunat ... Nima uchun men o'z fikrimni o'zgartirmadim, lekin kichik quti faqat ochildi: modul pinlaridan biri VCC ga ulanishi kerak edi. Mening holatimda modul quvvat manbai uchun 5V ni qo'llab-quvvatladi, shuning uchun ikki marta o'ylamasdan, moduldan keladigan simni taxtaning qarama-qarshi tomoniga uladim. Natijada, egri lehimli konnektor qiyshayib ketdi va UART aloqasi shunchaki yo'qoldi. facepalm.jpg Umuman olganda, “yomon bosh oyoqqa orom bermaydi”, qiyshiq qo‘llar esa boshga tinchlik bermaydi...

Natijada men uzoq kutilgan narsani ko'rdim

INIT
CMD0
CMD8
ACMD41
CMD58
CMD16
CMD18
LOADING /

Bundan tashqari, u harakat qiladi va yuklash indikatori aylanadi. Darhol maktab kunlarimni va MinuetOS-ni floppi diskdan bemalol yuklaganimni eslayman. Drayv silliqlashmasa.

Muammo shundaki, BOOT xabaridan keyin hech narsa sodir bo'lmaydi. Bu shuni anglatadiki, OpenOCD orqali Raspberry-ga, xostdagi GDB-ga ulanish va uning nima ekanligini ko'rish vaqti keldi.

Birinchidan, GDB yordamida ulanish darhol buni ko'rsatdi $pc (dastur hisoblagichi, joriy ko'rsatma manzili) ga uchadi 0x0 - bu, ehtimol, bir nechta xatolardan keyin sodir bo'ladi. Shuning uchun, xabar chiqarilgandan so'ng darhol BOOT Keling, cheksiz halqa qo'shamiz. Bu uni biroz vaqtga kechiktiradi ...

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

Bunday hiyla-nayrang kod "ishonchlilik uchun" ishlatiladi: men qaerdadir cheksiz tsikl aniqlanmagan xatti-harakat ekanligini eshitdim, lekin kompilyator taxmin qila olmaydi (sizga eslatib o'taman: 0x10000 BootROM joylashgan).

3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

Ko'rinishidan, yana nimani kutish kerak - qattiq o'rnatilgan, qanday manba kodlari bor? Lekin ichida o'sha maqola muallif C kodini tuzatayotgan edi... 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-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

Siz shunchaki MIF fayli yoki qutini emas, balki ELF formatidagi asl nusxasini yuklab olishingiz kerak.

Endi siz n-urinishda bajarilish davom etadigan manzilni taxmin qilishingiz mumkin (bu kompilyator tsiklning cheksiz ekanligini taxmin qilmasligining yana bir sababi). Jamoa

set variable $pc=0xADDR

registr qiymatini tezda o'zgartirishga imkon beradi (bu holda, joriy ko'rsatma manzili). Uning yordami bilan siz xotiraga yozilgan qiymatlarni o'zgartirishingiz mumkin (va xotira xaritasi registrlari).

Oxir-oqibat, men (qaysi biri to'g'ri ekanligiga ishonchim komil emas) bizda "noto'g'ri tizimning SD-karta tasviri" bor degan xulosaga keldim va biz yuklab olingan ma'lumotlarning eng boshiga emas, balki 0x89800 yana bayt:

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

Ehtimol, bunga qo'limda keraksiz 4 Gb karta yo'qligi sababli men 2 Gb kartani olib, tasodifiy Makefile-ga almashtirganim ham ta'sir qilgandir. DEMO_END=11718750 haqida DEMO_END=3078900 (aniq ma'noda ma'no izlamang - yo'q, shunchaki rasm kartaga joylashtirilgan).

Ikkinchi daraja, U-Boot

Endi biz hali ham "tushib ketyapmiz", lekin biz allaqachon to'g'ri joydamiz 0x0000000080089a84. Bu erda tan olishim kerak: aslida taqdimot "barcha to'xtashlar bilan" o'tmaydi, lekin qisman "keyin" deb yoziladi, shuning uchun men allaqachon SoC-dan to'g'ri dtb faylini kiritishga muvaffaq bo'ldim, uni sozlamalarda to'g'rilab qo'ydim. HiFive_U-Boot o'zgaruvchan CONFIG_SYS_TEXT_BASE=0x80089800 (o'rniga 0x08000000) yuklab olish manzili haqiqiy manzilga mos kelishi uchun. Endi biz keyingi darajadagi xaritani, boshqa rasmni yuklaymiz:

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

Va biz ko'ramiz:

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

Bundan tashqari, biz 308 va 309 qatorlar orasiga o'tamiz. Va bu ajablanarli emas. $sp ma'no yotadi 0xfffffffe31cdc0a0. Afsuski, u ham 307-qator tufayli doimiy ravishda “qochib ketadi”. Shuning uchun, toʻxtash nuqtasini oʻrnatishga harakat qilaylik. trap_entry, va keyin ga qayting 0x80089800 (U-Bootning kirish nuqtasi) va keling, u o'tishdan oldin registrlarni to'g'ri o'rnatishni talab qilmaydi deb umid qilaylik... Ishlayotganga o'xshaydi:

(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

Ochig'ini aytganda, stek ko'rsatkichi shunday: u RAMni butunlay chetlab o'tishni ko'rsatadi (agar, albatta, bizda manzil tarjimasi bo'lmasa, lekin oddiy variantga umid qilaylik).

Keling, ko'rsatgichni bilan almashtirishga harakat qilaylik 0x881cf950. Natijada shunday xulosaga kelamiz handle_trap qo'ng'iroq qildi va qo'ng'iroq qildi va shu bilan birga biz kiramiz _exit_trap argument bilan epc=2148315240 (o'nlik bo'yicha):

(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

To'xtash nuqtasini o'rnating strnlen, biz davom etamiz va ko'ramiz:

(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

Bo'lishi mumkin, _exit_trap yuzaga kelgan istisno haqida disk raskadrovka ma'lumotlarini taqdim qilmoqchi, lekin qila olmaydi. Shunday qilib, qandaydir tarzda bizning manbalarimiz yana ko'rsatilmaydi. set directories ../freedom-u-sdk/HiFive_U-Boot/ HAQIDA! Endi ko'rsatiladi!

Keling, uni yana ishga tushiramiz va stekdan birinchi xatoga sabab bo'lgan asl muammoning sababini ko'rib chiqamiz (mcause == 5). Agar nima yozilganini to'g'ri tushunsam shu yerda 37-betda, keyin bu istisno degani Load access fault. Buning sababi shu erda bo'lganga o'xshaydi

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 bir xil noto'g'ri ma'noga ega va ichida board_init_f_init_reserve xatolik yuzaga keladi. Bu aybdorga o'xshaydi: aniq nomga ega o'zgaruvchi CONFIG_SYS_INIT_SP_ADDR. Bu faylda aniqlangan HiFive_U-Boot/include/configs/HiFive-U540.h. Bir payt men hatto protsessor uchun yuklash moslamasini qo'shishim kerak deb o'yladim - balki protsessorni biroz tuzatish osonroq bo'larmidi? Ammo keyin men bu ko'proq to'liq tugallanmagan artefaktga o'xshashligini ko'rdim#if 0-boshqa xotira konfiguratsiyasi uchun maxsus sozlamalar va buni amalga oshirishga urinib ko'rishingiz mumkin:

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

Bir nuqtada tayoqchalar soni texnologik mahkamlagichlar tanqidiy nuqtaga yetdi. Bir oz kurashganimdan so'ng, men taxtam uchun to'g'ri portni qilish zarurligiga keldim. Buning uchun biz konfiguratsiyamizga mos keladigan bir qancha fayllarni nusxalashimiz va sozlashimiz kerak.

Xo'sh, taxminan, bu erda kichik stol bor

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

    Initial support for Zeowaa A-E115FB board

M       arch/riscv/Kconfig
A       arch/riscv/cpu/zeowaa-1gb/Makefile
A       arch/riscv/cpu/zeowaa-1gb/cpu.c
A       arch/riscv/cpu/zeowaa-1gb/start.S
A       arch/riscv/cpu/zeowaa-1gb/timer.c
A       arch/riscv/cpu/zeowaa-1gb/u-boot.lds
M       arch/riscv/dts/Makefile
A       arch/riscv/dts/zeowaa-1gb.dts
A       board/Zeowaa/zeowaa-1gb/Kconfig
A       board/Zeowaa/zeowaa-1gb/MAINTAINERS
A       board/Zeowaa/zeowaa-1gb/Makefile
A       board/Zeowaa/zeowaa-1gb/Zeowaa-A-E115FB.c
A       configs/zeowaa-1gb_defconfig
A       include/configs/zeowaa-1gb.h

Tafsilotlar bilan tanishishingiz mumkin omborlar.

Ma'lum bo'lishicha, ushbu SiFive platasida ba'zi qurilmalar registrlari turli xil manzillarga ega. Bundan tashqari, U-Boot Linux yadrosidan allaqachon tanish bo'lgan Kconfig mexanizmi yordamida sozlanganligi ma'lum bo'ldi - masalan, siz buyruq berishingiz mumkin. make menuconfig, va sizning oldingizda parametrlarning tavsiflarini ko'rsatadigan qulay matn interfeysi paydo bo'ladi ? va hokazo. Umuman olganda, ikkita plataning tavsifidan uchinchisining tavsifini birlashtirib, u erdan har qanday dabdabali PLL rekonfiguratsiyasini chiqarib tashladik (ko'rinishidan, bu qandaydir tarzda PCIe orqali asosiy kompyuterdan boshqarish bilan bog'liq, ammo bu aniq emas) , Men Marsda to'g'ri ob-havo sharoitida UART orqali u qaysi xeshdan tuzilganligi va menda qancha DRAM borligi haqida xabar bergan ba'zi proshivka oldim (lekin men o'zim bu ma'lumotni sarlavhada yozganman).

Afsuski, shundan keyin plata odatda JTAG protsessori orqali javob berishni to'xtatdi va SD-kartadan yuklash, afsuski, mening konfiguratsiyamda tez emas. Boshqa tomondan, ba'zida BootROM bu haqda xabar berdi ERROR, yuklanmadi va U-Boot darhol paydo bo'ldi. O'shanda bu menga tushdi: aftidan, bit oqimini FPGA-ga qayta ishga tushirgandan so'ng, xotira o'chirilmaydi, "mashqdan chiqarish" uchun vaqt yo'q va hokazo. Muxtasar qilib aytganda, siz shunchaki xabar paydo bo'lganda mumkin LOADING / tuzatuvchi va buyruq bilan ulaning set variable $pc=0x80089800, shu bilan bu uzoq yuklashni chetlab o'tish (albatta, oxirgi marta u etarlicha erta buzilgan va asl kodning ustiga hech narsa yuklashga ulgurmagan degan taxmin bilan).

Aytgancha, protsessorning to'liq muzlashi va JTAG tuzatuvchisi unga xabarlar bilan ulana olmasligi odatda normalmi?

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

Xo'sh, kuting! Men buni allaqachon ko'rganman! TileLink blokirovka qilinganda shunga o'xshash narsa sodir bo'ladi va men qandaydir tarzda xotira kontrolleri muallifiga ishonmayman - men buni o'zim yozganman ... To'satdan, kontrollerni tahrir qilgandan so'ng protsessorni birinchi muvaffaqiyatli qayta qurishdan so'ng, men ko'rdim:

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

Oldin bu g'alati chiziqqa In: serial e'tibor bermang - men osilgan protsessorda uning atrof-muhit bilan to'g'ri ishlashini tushunishga harakat qilardim. "O'n daqiqadan beri shunday osilgan" deganingiz nimani anglatadi? Hech bo'lmaganda u boshqa joyga ko'chib o'tishga va yuklash menyusiga o'tishga muvaffaq bo'ldi! Kichkina chekinish: U-Boot SD-kartadan dastlabki 2^24 baytda yuklangan bo'lsa-da, u ishga tushirilganda o'zini konfiguratsiya sarlavhasida yozilgan uzoqroq manzilga yoki oddiygina operativ xotiraning yuqori manzillariga ko'chiradi. , va ELF ko'chirish -belgilarni amalga oshiradi va u erda boshqaruvni uzatadi. Shunday qilib: biz bu darajadan o'tganga o'xshaymiz va bundan keyin protsessor mahkam osib qo'yilmagani uchun bonus oldik.

Xo'sh, nega taymer ishlamayapti? Negadir soat ishlamayapti shekilli...

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

Agar o'qlarni qo'lda aylantirsangiz nima bo'ladi?

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

Keyin:

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

Xulosa: soat tiqilmayapti. Ehtimol, shuning uchun klaviatura kiritish ishlamaydi:

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

Muammo shundaki, men juda aqlli edim: men kalitni protsessor konfiguratsiyasiga qo'shdim:

  case DTSTimebase => BigInt(0)

... izohda "agar bilmasangiz, 0 qo'ying" deb yozilganiga asoslanib. Va nihoyat WithNBigCores Men uni 1 MGts ga o'rnatdim (aytmoqchi, u U-Boot konfiguratsiyasida ko'rsatilgan). Lekin la'nat, men toza va sinchkovman: u erda bilmayman, bu erda 25 MGts! Oxir-oqibat, hech narsa ishlamaydi. Men "yaxshilanishlarimni" olib tashladim va...

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 #

Siz hatto buyruqlar kiritishingiz mumkin! Misol uchun, bir oz aylanib yurganingizdan so'ng, siz nihoyat kirishni taxmin qilishingiz mumkin mmc_spi 1 10000000 0; mmc part, SPI chastotasini 20 MGts dan 10 MGts gacha kamaytirish. Nega? Xo'sh, 20MHz maksimal chastotasi konfiguratsiyada yozilgan va u hali ham u erda yozilgan. Lekin, men tushunganimdek, interfeyslar, hech bo'lmaganda, bu erda ishlaydi: kod apparat birligining chastotasini (meniki hamma joyda 25 MGts) maqsad bo'yicha ajratadi va natijada olingan qiymatni tegishli boshqaruvda bo'linuvchi sifatida o'rnatadi. ro'yxatdan o'tish. Muammo shundaki, agar 115200 Gts chastotali UART uchun taxminan zarur bo'lgan narsa bo'lsa, 25000000 ni 20000000 ga bo'lsangiz, siz 1 ni olasiz, ya'ni. u 25 MGts chastotada ishlaydi. Ehtimol, bu normaldir, lekin agar cheklovlar o'rnatilgan bo'lsa, demak, kimdir bunga muhtoj (lekin bu aniq emas) ... Umuman olganda, uni o'rnatish va davom ettirish osonroq - uzoq va, afsuski, uzoq vaqt. 25 MGts Core i9 emas.

Konsol chiqishi

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

Mayli, biz keyingi bosqichga yetdik, lekin u hali ham sovuq. Va ba'zida u ham istisnolarni sepadi. Ko'rsatilgan manzilda kodni kutish orqali mcauseni ko'rishingiz mumkin $pc va keyin si bo'l trap_entry. U-Boot ishlov beruvchisining o'zi faqat mcause = 0..4 uchun chiqishi mumkin, shuning uchun noto'g'ri yuklashda qolib ketishga tayyor bo'ling. Keyin men konfiguratsiyaga kirdim, nimani o'zgartirayotganimni ko'rishni boshladim va esladim: u erda conf/rvboot-fit.txt yozilgan:

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

Keling, barcha fayllarni moslashtiraylik, yadro buyruq qatorini shunga o'xshash narsa bilan almashtiraylik, chunki shubhalar mavjud. SIF0 - bu PCIe orqali chiqadigan joy:

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

Va keling, xeshlash algoritmini SHA-256 dan MD5 ga o'zgartiraylik: menga kriptografik kuch kerak emas (ayniqsa disk raskadrovka paytida), bu juda uzoq vaqt talab etadi va yuklash paytida yaxlitlik xatolarini aniqlash uchun MD5 juda oson. Yakuniy natija nima? Biz oldingi darajani sezilarli darajada tezroq yakunlay boshladik (oddiyroq xeshlash tufayli) va keyingisi ochildi:

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

Lekin soat taqillamayapti...

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

Voy, soatni to'g'rilash platsebo bo'lib chiqdi, garchi o'sha paytda menga yordam bergandek tuyuldi. Yo'q, albatta, uni tuzatish kerak, lekin avval o'qlarni qo'lda aylantiramiz va nima bo'lishini ko'raylik:

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.

Shu vaqtda…

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

Yo'q, men soatni avtomatlashtirishga boraman - aks holda u o'sha erda taymerni sozlashga qaror qiladi!

Ayni paytda, joriy yo'riqnomaning manzili biron bir joyga ishora qiladi

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>

yuklangan Berkeley Boot Loader ichida. Shaxsan meni bu haqda chalg'itadigan narsa bu eslatma htif — yadroni bogʻlangan ishga tushirish uchun foydalaniladigan xost interfeysi (yaʼni ARM xost bilan hamkorlikda), men mustaqil deb hisobladim. Ammo, agar siz ushbu funktsiyani manba kodida topsangiz, hamma narsa unchalik yomon emasligini ko'rishingiz mumkin:

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

Topshiriq: soatni boshlang

CLINT da registrlarni qidirish bizni olib boradi

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

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

Qaysi biri RTC yoki sirli MockAON bilan bog'lanadi, men dastlab o'ylagan edim: “Xo'sh, bu erda bizda nima bor? Tushunarsiz? Keling, uni o'chiraylik!" Men u erda qanday soat sehri sodir bo'layotganini hali ham tushunmaganim uchun, men bu mantiqni qayta ishlataman. 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 yadrosiga yo'l olamiz

Bu erda hikoya allaqachon cho'zilgan va biroz monoton bo'lib qolgan, shuning uchun men uni yuqoridan pastgacha tasvirlab beraman:

BBL da FDT mavjudligini taxmin qildi 0xF0000000, lekin men uni allaqachon tuzatdim! Xo'sh, keling, yana ko'rib chiqaylik ... Uni ichidan topdim HiFive_U-Boot/arch/riscv/lib/boot.c, bilan almashtirildi 0x81F00000, U-Boot yuklash konfiguratsiyasida ko'rsatilgan.

Keyin BBL xotira yo'qligidan shikoyat qildi. Mening yo'lim funktsiyada edi mem_prop, qaysi riscv-pk/machine/fdt.c: u yerdan men fdt ram tugunini shunday belgilash kerakligini bilib oldim device_type = "memory" - keyin, ehtimol, protsessor generatorini tuzatish kerak bo'ladi, lekin hozircha men uni qo'lda yozaman - baribir, men ushbu faylni qo'lda o'tkazdim.

Endi men xabarni oldim (formatlangan shaklda, vagon qaytarilishi bilan):

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.

Variantlar kerak bo'lganda ko'rsatilganga o'xshaydi riscv,kernel-start и riscv,kernel-end DTB da, lekin nollar tahlil qilinadi. Nosozliklarni tuzatish query_chosen BBL 32-bitli manzilni tahlil qilishga urinayotganini ko'rsatdi, lekin u juftlikka duch keladi <0x0 0xADDR>, va birinchi qiymat eng kam ahamiyatli bitlar kabi ko'rinadi. Bo'limga qo'shildi chosen

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

va qadriyatlar avlodini tuzatdi: qo'shmang 0x0 birinchi element.

Ushbu 100500 XNUMX oddiy qadam pingvinning qulashini kuzatishni osonlashtiradi:

Yashirin matn

   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 BBL tomonidan, vaqt belgilariga ega bo'lgan esa yadro tomonidan ko'rsatiladi).

Yaxshiyamki, bu hamma joyda qandayligini bilmayman, lekin RocketChip-da, JTAG orqali tuzatuvchini ulaganingizda, siz qutidan tuzoqlarni ushlashingiz mumkin - tuzatuvchi aynan shu nuqtada to'xtaydi.

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

Eski hazil aytganidek, CPU topilmadi, dasturiy ta'minot emulyatsiyasi ishlaydi. Xo'sh, yoki yugurmaslik. Bitta protsessor yadrosida yo'qolgan.

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

Yaxshi izoh linux/arch/riscv/kernel/setup.c - Tom Soyer usuli yordamida devorni bo'yashning bir turi. Umuman, bugun negadir g‘oliblar aniqlanmadi, sovrin keyingi o‘yinga o‘tkazildi...

Bu erda men allaqachon uzoq bo'lgan maqolani tugatishni taklif qilaman.

Davomi bor. Agar siz asta-sekin yakka qadam bilan o'rmalab chiqsangiz, yashirinishga muvaffaq bo'lgan ayyor xato bilan kurash bo'ladi.

Matnni yuklab olish skrinshoti (tashqi havola):
3-qism: Linux SD-kartadan RocketChip-ga deyarli yuklanmoqda

Manba: www.habr.com

a Izoh qo'shish