Bagian 3: Hampir memuat Linux dari kartu SD ke RocketChip

Pada bagian sebelumnya , pengendali memori yang bekerja kurang lebih diimplementasikan, atau lebih tepatnya, pembungkus IP Core dari Quartus, yang merupakan adaptor untuk TileLink. Hari ini, di bawah judul "Kami port RocketChip ke motherboard Cina yang sedikit dikenal dengan Cyclone", Anda akan melihat konsol yang berfungsi. Proses berjalan sedikit: Saya sudah berpikir bahwa saya akan segera meluncurkan Linux, dan melanjutkan, tetapi tidak ada di sana. Pada bagian ini, saya mengusulkan untuk melihat proses memulai U-Boot, BBL, dan upaya Linux yang malu-malu untuk menginisialisasi. Tetapi ada konsol - U-Boot-ovsky, dan cukup canggih, memiliki banyak dari apa yang Anda harapkan dari konsol penuh.


Dalam perangkat keras, kartu SD yang terhubung melalui SPI, serta UART, akan ditambahkan. Pada bagian perangkat lunak, BootROM akan diganti dari xip ke sdboot dan, pada kenyataannya, tahapan boot berikut (pada kartu SD) akan ditambahkan.


Doping perangkat keras


Jadi, tugasnya: Anda perlu beralih ke inti "besar" dan menghubungkan UART (dari Raspberry) dan adaptor SD (semacam papan Catalex dengan enam pin digunakan: GND, VCC, MISO, MOSI, SCK, CS).


Pada prinsipnya, semuanya cukup sederhana. Tetapi sebelum menyadari ini, saya dilemparkan sedikit dari sisi ke sisi: setelah waktu sebelumnya, saya memutuskan bahwa Anda hanya perlu mencampur sesuatu seperti HasPeripheryUART ke dalam System (dan implementasinya, masing-masing), sama untuk kartu SD - dan hanya itu akan siap. Kemudian saya memutuskan untuk melihat bagaimana itu diterapkan dalam desain "serius". Jadi apa yang kita dapatkan dengan serius? Arty, tampaknya, tidak cocok - monster itu tetap tidak unleahshed.DevKitConfigs . unleahshed.DevKitConfigs . Dan tiba-tiba ternyata di mana-mana ada semacam overlay yang ditambahkan melalui parameter dengan kunci. Saya kira ini mungkin sangat fleksibel dan dapat dikonfigurasi, tetapi saya ingin memulai sesuatu untuk permulaan ... Tetapi Anda tidak memiliki kruk yang sama, lebih mudah? .. Lalu saya menemukan vera.iofpga.FPGAChip untuk FPGA Microsemi dan segera menarik tanda kutip Saya mencoba membuat implementasi saya dengan analogi, manfaatnya di sini adalah kurang lebih seluruh "layout motherboard" dalam satu file.


Ternyata, sungguh, Anda hanya perlu menambahkan baris ke 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 ... 

Baris di badan kelas System menambahkan informasi tentang frekuensi di mana bagian dari SoC kami ini bekerja pada file dts. Sejauh yang saya mengerti, DTS / DTB adalah analog statis teknologi plug-and-play untuk perangkat yang disematkan: pohon dts-description dikompilasi menjadi file dtb biner dan ditransmisikan oleh loader ke kernel sehingga dapat dengan benar mengkonfigurasi perangkat keras. Menariknya, tanpa garis dengan tlclock semuanya disintesis dengan sempurna, tetapi tidak akan berfungsi untuk mengkompilasi BootROM (saya akan mengingatkan Anda sekarang akan sdboot ) - selama kompilasi ia mem-parsing file dts dan membuat header dengan makro TL_CLK , berkat yang dapat dengan benar mengkonfigurasi pembagi frekuensi untuk antarmuka eksternal.


Anda juga perlu sedikit memperbaiki "kabel":


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 } 

Rantai daftar, terus terang, ditambahkan hanya dengan analogi dengan beberapa tempat lain dalam kode sumber. Kemungkinan besar, mereka harus melindungi terhadap metastabilitas . Mungkin beberapa blok sudah memiliki perlindungan sendiri, tetapi pertama-tama saya ingin menjalankan setidaknya "pada level tinggi." Pertanyaan yang lebih menarik bagi saya adalah mengapa MISO dan MOSI bertahan pada dq berbeda? Saya masih belum menemukan jawabannya, tetapi tampaknya sisa kode hanya mengandalkan koneksi semacam itu.


Secara fisik, saya baru saja menetapkan kesimpulan desain untuk kontak longgar di blok dan mengatur ulang jumper pemilihan tegangan ke 3.3V.


Adaptor SD

Tampilan atas:



Tampak bawah:



Debugging bagian perangkat lunak: alat


Pertama, mari kita bicara tentang alat debugging yang tersedia dan batasannya.


Minicom


Pertama, kita perlu membaca entah apa bootloader dan output kernel. Untuk melakukan ini, di Linux (dalam hal ini, yang ada di RaspberryPi), kita memerlukan program Minicom. Secara umum, setiap program untuk bekerja dengan port serial cocok.


Perhatikan bahwa pada saat startup, nama perangkat port harus ditentukan sebagai -D /dev/ttyS0 - setelah opsi -D . Nah, informasi utama: untuk keluar, gunakan Ctrl-A, X Saya benar-benar memiliki kasus di mana kombinasi ini tidak berfungsi - maka Anda dapat mengatakan killall -KILL minicom dari sesi SSH yang berdekatan.


Ada fitur lain. Secara khusus, ada dua UART pada RaspberryPi, dan kedua port sudah dapat diadaptasi untuk sesuatu: satu untuk Bluetooth, melalui yang lain, konsol kernel ditampilkan secara default. Untungnya, perilaku ini dapat dikonfigurasi ulang sesuai dengan manual ini .


Memori penulisan ulang


Saat debugging, untuk menguji hipotesis, saya terkadang harus memuat bootloader (maaf) ke dalam RAM langsung dari host. Mungkin ini bisa dilakukan langsung dari GDB, tetapi pada akhirnya saya pergi dengan cara sederhana: Saya menyalin file yang diperlukan ke Raspberry, juga mengirim port 4444 (telnet dari OpenOCD) melalui SSH dan menggunakan perintah load_image . Ketika Anda mengeksekusinya, tampaknya semuanya membeku, tetapi sebenarnya "tidak tidur, hanya berkedip perlahan" : ia memuat file, ia hanya melakukannya dengan kecepatan beberapa kilobyte per detik.


Fitur menginstal breakpoints


Mungkin, banyak yang tidak perlu memikirkan hal ini ketika men-debug program reguler, tetapi breakpoint tidak selalu diatur dalam perangkat keras. Kadang-kadang pengaturan breakpoint melibatkan sementara menulis instruksi khusus ke tempat yang tepat secara langsung dalam kode mesin . Sebagai contoh, ini adalah cara kerja perintah standar saya di GDB. Inilah yang berikut dari ini:


  • Anda tidak dapat memasukkan titik di dalam BootROM, karena ROM
  • Anda dapat mengatur breakpoint pada kode yang dimuat ke dalam RAM dari kartu SD, tetapi Anda harus menunggu sampai itu dimuat. Kalau tidak, kami tidak akan menulis ulang sepotong kode, tetapi loader akan menulis ulang breakpoint kami

Saya yakin Anda dapat secara eksplisit meminta untuk menggunakan breakpoint perangkat keras, tetapi ada beberapa yang terbatas.


Swap BootROM cepat


Pada tahap awal debugging, sering kali ada keinginan untuk memperbaiki BootROM dan coba lagi. Tetapi ada masalah: BootROM adalah bagian dari desain yang dimuat ke dalam FPGA, dan sintesisnya adalah masalah beberapa menit (dan ini setelah hampir secara instan mengkompilasi gambar BootROM itu sendiri dari C dan Assembler ...). Untungnya, pada kenyataannya, semuanya jauh lebih cepat : urutan tindakan adalah sebagai berikut:


  • meregenerasi bootrom.mif (saya beralih ke MIF alih-alih HEX, karena dengan HEX saya selalu memiliki beberapa masalah, dan MIF adalah format asli Alter)
  • di Quartus say Processing -> Update Memory Initialization File
  • pada Assembler (di kolom sebelah kiri Tugas), perintah Mulai lagi

Untuk semuanya tentang segalanya - beberapa puluh detik.


Persiapan kartu SD


Semuanya relatif sederhana di sini, tetapi Anda harus bersabar dan memiliki sekitar 14Gb ruang disk:


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

Maka Anda perlu memasukkan bersih, atau lebih tepatnya, tidak mengandung apa pun yang Anda butuhkan, kartu SD, dan jalankan


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

... di mana sdX adalah perangkat yang ditetapkan untuk kartu. PERHATIAN: data pada kartu akan dihapus, ditimpa dan umumnya! Hampir tidak layak melakukan seluruh perakitan dari bawah sudo , karena semua artefak perakitan akan dimiliki oleh root , dan perakitan harus dilakukan dari bawah sudo waktu.


Hasilnya adalah kartu yang ditandai dalam GPT dengan empat bagian, di mana salah satunya adalah FAT dengan uEnv.txt dan gambar yang dapat diunduh dalam format FIT (berisi beberapa sub-gambar, masing-masing dengan alamat unduh sendiri), bagian lain kosong, seharusnya diformat dalam Ext4 untuk Linux. Dua bagian lagi bersifat samar : U-Boot hidup dengan satu (offsetnya, seperti yang saya pahami, ditransfer dalam BootROM), di sisi lain, sepertinya variabel lingkungannya hidup, tetapi saya belum menggunakannya.


Tingkat Satu, BootROM


Kebijaksanaan rakyat mengatakan: "Jika dalam pemrograman ada tarian dengan rebana, maka dalam elektronik - juga dengan pemadam api." Bahkan tidak begitu saya hampir membakar papan, memutuskan bahwa "Yah, GND adalah tingkat rendah yang sama" (tampaknya, resistor masih tidak akan sakit ...) Ini lebih lanjut tentang fakta bahwa jika tangan tidak tumbuh dari sana, maka elektronik tidak berhenti membawa kejutan: ketika saya menyolder konektor ke papan, saya masih tidak bisa membubarkan kontak secara normal - video menunjukkan bagaimana solder langsung menyebar ke seluruh koneksi, hanya memasukkan besi solder, itu sudah turun pada saya bagaimanapun juga. Yah, mungkin soldernya tidak cocok untuk suhu besi solder, mungkin sesuatu yang lain ... Secara umum, ketika saya melihat bahwa saya sudah memiliki selusin kontak, saya meludah, dan mulai men-debug. Dan kemudian hal yang misterius dimulai: Saya menghubungkan RX / TX dari UART, saya memuat firmware - ia menulis


 INIT CMD0 ERROR 

Yah, semuanya logis - saya tidak menghubungkan modul kartu SD. Kami memperbaiki situasi, memuat firmware ... Dan diam ... Apa yang saya tidak berubah pikiran, dan peti mati baru saja terbuka: salah satu output modul harus terhubung ke VCC. Dalam kasus saya, modul mendukung 5V untuk daya, jadi tanpa berpikir dua kali, saya memasang kawat yang membentang dari modul ke sisi yang berlawanan dari papan. Akibatnya, konektor yang disolder bengkok memutar, dan kontak UART hilang begitu saja. facepalm.jpg Secara umum, "kepala yang buruk tidak memberi istirahat pada kaki", dan tangan yang bengkok - ke kepala ...


Pada akhirnya, saya melihat yang sudah lama ditunggu-tunggu di Minicom


 INIT CMD0 CMD8 ACMD41 CMD58 CMD16 CMD18 LOADING / 

Selain itu, itu bergerak indikator pemuatan berputar. Saya langsung mengingat tahun-tahun sekolah dan boot santai MinuetOS dari floppy disk. Kecuali jika drive berputar.


Masalahnya adalah bahwa tidak ada yang terjadi setelah pesan BOOT. Jadi, inilah saatnya untuk terhubung melalui OpenOCD pada Raspberry, GDB pada host untuk itu, dan lihat apa itu.


Pertama, terhubung dengan GDB segera menunjukkan bahwa $pc (program counter, alamat dari instruksi saat ini) terbang ke 0x0 - ini mungkin terjadi setelah beberapa kesalahan. Oleh karena itu, segera setelah pesan BOOT dikeluarkan, kami menambahkan loop tak terbatas. Ini akan menunda dia sebentar ...


 diff --git a/bootrom/sdboot/sd.cb/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; } 

Kode rumit semacam itu digunakan "untuk keandalan": Saya mendengar di suatu tempat bahwa, tampaknya, infinite loop adalah Perilaku Tidak Terdefinisi, dan di sini kompiler tidak mungkin menebak (saya ingat bahwa BootROM terletak di 0x10000 ).


Ada debugger, tidak ada sumber


Tampaknya, tapi apa lagi yang diharapkan - tertanam keras, sumber apa yang ada di sana. Tapi bagaimanapun, dalam artikel itu, penulis men-debug kode ... Krex-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. 

Ada kode sumber!


Hanya Anda yang perlu memuat bukan file MIF dan bukan bin, tetapi versi asli dalam format ELF.


Sekarang, dengan upaya ke-n untuk menebak alamat di mana eksekusi akan berlanjut (ini adalah alasan lain mengapa kompiler seharusnya tidak menebak bahwa loop tidak terbatas). Tim


 set variable $pc=0xADDR 

memungkinkan Anda untuk mengubah nilai register saat bepergian (dalam hal ini, alamat instruksi saat ini). Dengan bantuannya, Anda dapat mengubah nilai yang direkam dalam memori (dan register yang dipetakan memori).


Pada akhirnya, saya sampai pada kesimpulan (tidak yakin apakah itu benar) bahwa kita memiliki "gambar kartu sd dari sistem yang salah", dan kita harus pergi bukan ke awal data yang diunduh, tetapi ke 0x89800 byte lebih lanjut:


 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 

Mungkin ini juga dipengaruhi oleh fakta bahwa saya tidak memiliki kartu 4Gb yang tidak perlu, saya membawanya ke 2Gb dan menggantinya di Makefile dengan DEMO_END=11718750 dengan DEMO_END=3078900 (tidak mencari arti dalam nilai tertentu - tidak ada, hanya sekarang gambar ditempatkan, hanya sekarang gambar ditempatkan ke kartu).


Tingkat Dua, U-Boot


Sekarang kita masih "jatuh", tetapi kita sudah berada di alamat 0x0000000080089a84 . Di sini saya harus mengakui: sebenarnya, presentasi tidak berjalan "dengan semua berhenti", tetapi sebagian ditulis "setelah", jadi di sini saya sudah berhasil menempatkan file dtb yang benar dari SoC kami, sesuaikan variabel CONFIG_SYS_TEXT_BASE=0x80089800 dalam pengaturan HiFive_U-Boot (bukan 0x08000000 ) sehingga alamat unduhan cocok dengan yang sebenarnya. Unduh sekarang peta tingkat berikutnya gambar lain:


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

Dan kita melihat:


  β”‚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) β”‚ 

Dan kami melompat di antara baris 308 dan 309. Dan tidak mengherankan, mengingat bahwa $sp berisi nilai 0xfffffffe31cdc0a0 . Sayangnya, itu juga terus-menerus "lari" karena jalur 307. Oleh karena itu, kami akan mencoba untuk menetapkan breakpoint pada trap_entry , dan kemudian kembali beralih ke 0x80089800 (titik masuk Boot-U), dan kami berharap tidak memerlukan pengaturan register yang benar sebelum transisi. ... Tampaknya bekerja:


 (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 

So-so, stack pointer, katakan terus terang: umumnya menunjuk melewati RAM (kecuali, tentu saja, kami masih memiliki terjemahan alamat, tetapi mari kita berharap untuk opsi yang sederhana).


Mari kita coba ganti pointer dengan 0x881cf950 . Akibatnya, kita sampai pada fakta bahwa handle_trap dipanggil dan dipanggil, sambil meninggalkan _exit_trap dengan argumen epc=2148315240 (dalam desimal):


 (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 

Kami menetapkan breakpoint pada strnlen , melanjutkan dan melihat:


 (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 %08lx\n", fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lx\n", 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 %08lx\n", 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 %08lx\n", args=args@entry=0x881cc188) at lib/vsprintf.c:717 #5 0x00000000800ccb50 in printf (fmt=fmt@entry=0x800d4458 "exception code: %d , %s , epc %08x , ra %08lx\n") 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 

Tampaknya _exit_trap ingin memberikan informasi debug tentang pengecualian yang terjadi, tetapi gagal . Jadi, sesuatu dengan kode sumber kami tidak ditampilkan lagi. set directories ../freedom-u-sdk/HiFive_U-Boot/ Oh! Sekarang ditampilkan!


Nah, jalankan lagi dan lihat pada stack trace penyebab masalah asli yang menyebabkan kesalahan pertama ( mcause == 5 ). Jika saya mengerti benar apa yang tertulis di sini di halaman 37, maka pengecualian ini berarti Load access fault . Alasannya, rupanya, karena di sini


lengkung / 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 memiliki nilai salah yang sama, dan kesalahan terjadi di dalam board_init_f_init_reserve . Tampaknya itu penyebabnya: variabel dengan nama eksplisit CONFIG_SYS_INIT_SP_ADDR . Ini didefinisikan dalam file HiFive_U-Boot/include/configs/HiFive-U540.h . Pada titik tertentu, saya bahkan berpikir, atau mungkin, menyelesaikan bootloader untuk prosesor - mungkin lebih mudah untuk sedikit memperbaiki prosesor? Tapi kemudian saya melihat bahwa itu lebih seperti artefak dari pengaturan yang tidak sepenuhnya #if 0 untuk konfigurasi memori yang berbeda, dan Anda dapat mencoba melakukan ini:


 diff --git a/include/configs/HiFive-U540.hb/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\0" /* 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 */ 

Pada titik tertentu, kuantitas kruk pengencang teknologi mencapai titik kritis. Setelah sedikit siksaan, saya sampai pada kebutuhan untuk membuat port yang benar di papan saya. Untuk melakukan ini, Anda perlu menyalin dan memperbaiki sejumlah file untuk konfigurasi kami.


Nah, kira-kira, ini ada meja kecil
 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 

Detail dapat ditemukan di repositori .


Ternyata, pada papan SiFive ini, register dari beberapa perangkat memiliki alamat yang berbeda. Juga ternyata U-Boot dikonfigurasikan oleh mekanisme Kconfig, yang sudah biasa dari kernel Linux - misalnya, Anda dapat memerintahkan make menuconfig , dan Anda akan melihat antarmuka teks yang nyaman dengan deskripsi parameter yang ditunjukkan pada ? dll. Secara umum, setelah membutakan deskripsi yang ketiga dari deskripsi dua papan, membuang semua konfigurasi ulang PLL patos dari sana (tampaknya, ini entah bagaimana terhubung dengan kontrol PCIe dari komputer host, tapi ini tidak akurat), saya mendapatkan beberapa firmware, yang, jika cuacanya tepat di Mars Itu memberi saya pesan UART tentang hash komit mana itu dikumpulkan, dan berapa banyak DRAM yang saya miliki (tetapi saya juga mendaftarkan informasi ini di header).


Sangat disayangkan bahwa setelah ini board biasanya berhenti merespons dengan prosesor JTAG, dan booting dari kartu SD, sayangnya, tidak cepat dalam konfigurasi saya. Di sisi lain, kadang-kadang BootROM menampilkan pesan bahwa ERROR tidak dapat melakukan boot, dan U-Boot segera muncul. Saat itulah saya sadar: rupanya, setelah me-reboot bitstream, memori tidak rusak di FPGA, tidak punya waktu untuk "dihancurkan", dll. Singkatnya, Anda dapat dengan mudah ketika LOADING / pesan muncul, terhubung dengan debugger dan set variable $pc=0x80089800 perintah set variable $pc=0x80089800 , dengan demikian melewati unduhan panjang ini (tentu saja, dengan asumsi bahwa itu terakhir rusak cukup awal, dan tidak punya waktu di atas kode asli unduh).


Ngomong-ngomong, dan umumnya normal bahwa prosesor hang sepenuhnya dan debugger JTAG dengan pesan tidak dapat terhubung dengannya


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

Jadi tunggu! Saya sudah melihatnya! - 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 β€” , environment. , Β« Β»? ! : U-Boot 2^24 SD-, , , , , 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 1MHz (, , U-Boot). , , : , 25MHz! . «» ...


 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 20MHz 10MHz. Mengapa , 20MHz, . , , , , : ( β€” 25MHz) , . , 115200Hz UART- , , 25000000 20000000 1, .. 25MHz. , , , , - ( )… , β€” , , . 25MHz β€” 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 

, , . . mcause , $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 β€” . Apa hasilnya? ( ), :


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

Berkeley Boot Loader. htif β€” host interface, tethered- ( ARM), - standalone. , , , :


 void poweroff(uint16_t code) { printm("Power off\r\n"); finisher_exit(code); if (htif) { htif_poweroff(); } else { send_ipi_many(0, IPI_HALT); while (1) { asm volatile ("wfi\n"); } } } 

:


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 kernel


, :


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 , :


  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 trap- β€” .


 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 

freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:


 void __init setup_smp(void) { struct device_node *dn = NULL; int hart; bool found_boot_cpu = false; int cpuid = 1; while ((dn = of_find_node_by_type(dn, "cpu"))) { hart = riscv_of_processor_hartid(dn); if (hart < 0) continue; if (hart == cpuid_to_hartid_map(0)) { BUG_ON(found_boot_cpu); found_boot_cpu = 1; continue; } cpuid_to_hartid_map(cpuid) = hart; set_cpu_possible(cpuid, true); set_cpu_present(cpuid, true); cpuid++; } BUG_ON(!found_boot_cpu); // <    } 

, CPU not found, running software emulation . running. .


 /* 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 β€” . , - , ...


.


. , , singlestep-.


( ):
asciicast

Source: https://habr.com/ru/post/id458482/


All Articles