Част 4: Все пак стартираме Linux на RocketChip RISC-V

Част 4: Все пак стартираме Linux на RocketChip RISC-V На изображението Linux kernel ви отправя поздрави през GPIO.

В тази част от историята за портироването на RISC-V RocketChip на китайска платка с Cyclone IV, все пак ще стартираме Linux и ще научим как сами да конфигурираме IP Core контролера на паметта, а също така ще направим малки корекции в dts описанието на оборудването. Тази статия е продължение на третата част, но, за разлика от значително по-дългата предишна, тя ще бъде сравнително кратка.

… Тъй като setup_smp се извиква само ако ядрото е конфигурирано с поддръжка на SMP, можем да опитаме да изключим многопоточността. Неприятно ще бъде, ако трябва да реализирам поддръжка на атомарност в модула на паметта (ми се струва, че кеша се справя сам с това), но в едноядерния случай не трябва да ни пречи.

Въпреки това не проработи…

[    0.000000] OF: fdt: Игнориране на диапазона на паметта 0x80000000 - 0x80200000
[    0.000000] Linux версия 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc версия 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 Чет 4 юли 18:38:10 MSK 2019
[    0.000000] bootconsole [early0] разрешен
[    0.000000] Начална ramdisk на: 0x(____ptrval____) (16777216 байта)
[    0.000000] Зони диапазони:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Започване на преносима зона за всяка възел
[    0.000000] Ранни диапазони на паметта на възела
[    0.000000]   възел   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Настройка на initmem възел 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] софтуерен IO TLB: картографиран [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] Не е възможно да се намери "cpu" devicetree запис
[    0.000000] Изградени 1 zonelists, групиране на мобилността. Общо страници: 258055
[    0.000000] Командния ред на ядрото: debug console=ttySIF0,125200 root=\/dev\/mmcblk0p2 loglevel=7 rootwait
[    0.000000] Списък на кеша на дентризите: 131072 (поръчка: 8, 1048576 байта)
[    0.000000] Списък на кеша на inode: 65536 (поръчка: 7, 524288 байта)
[    0.000000] Сортиране на __ex_table...
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bf7
[    0.000000] страница:ffffffe03f029e08 брой:0 mapcount:-65280 mapping:0000000000000000 index:0x1
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 0000000000000100 0000000000000200 0000000000000000
[    0.000000] raw: 0000000000000001 0000000000000000 00000000ffff00ff
[    0.000000] страницата е разтоварена, защото: ненулев mapcount
[    0.000000] Свързани модули:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Не е замърсено 4.19.0-sifive-1+ #1
[    0.000000] Обаждане на трасето:
[    0.000000] [<ffffffe00002cfde>] walk_stackframe+0x0\/0xa0
[    0.000000] [<ffffffe00002d1da>] show_stack+0x2a\/0x34
[    0.000000] [<ffffffe00063c898>] chachachllachachachTradeonachachach_inachachipachachachachllachachachTradeonachachachdevachachachypachachachllachachachTradeona+0x20\/0x28
[    0.000000] [<ffffffe00009499c>] bad_page+0xe4\/0x102
[    0.000000] [<ffffffe0000949f2>] free_pages_check_bad+0x38\/0x7a
[    0.000000] [<ffffffe000094bb0>] free_pcppages_bulk+0x106\/0x36c
[    0.000000] [<ffffffe0000957be>] free_unref_page_commit.isra.23+0x86\/0x8e
[    0.000000] [<ffffffe0000960bc>] free_unref_page+0x44\/0x58
[    0.000000] [<ffffffe0000960de>] __free_pages.part.28+0xe\/0x22
[    0.000000] [<ffffffe0000056da>] __free_pages_bootmem+0x86\/0x90
[    0.000000] [<ffffffe000007c46>] free_all_bootmem+0x156\/0x1ba
[    0.000000] [<ffffffe0000023f8>] mem_init+0x36\/0x44
[    0.000000] [<ffffffe0000007a0>] start_kernel+0x1aa\/0x328
[    0.000000] [<ffffffe000000058>] _sinittext+0x58\/0x5c
[    0.000000] Деактивиране на отстраняването на грешки при блокировки поради замърсяване на ядрото
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bf9
[    0.000000] страница:ffffffe03f029e78 брой:0 mapcount:-65280 mapping:0000000000000000 index:0x0
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f020080 ffffffe03f020080 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] страницата е разтоварена, защото: ненулев mapcount
[    0.000000] Свързани модули:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Замърсено: G    B             4.19.0-sifive-1+ #1
[    0.000000] Обаждане на трасето:
[    0.000000] [<ffffffe00002cfde>] walk_stackframe+0x0\/0xa0
[    0.000000] [<ffffffe00002d1da>] show_stack+0x2a\/0x34
[    0.000000] [<ffffffe00063c898>] chachachllachachachTradeonachachach_inachachipachachachachllachachachTradeonachachachdevachachachypachachachllachachachTradeona+0x20\/0x28
[    0.000000] [<ffffffe00009499c>] bad_page+0xe4\/0x102
[    0.000000] [<ffffffe0000949f2>] free_pages_check_bad+0x38\/0x7a
[    0.000000] [<ffffffe0000955c6>] __free_pages_ok+0x3fe\/0x430
[    0.000000] [<ffffffe0000960ea>] __free_pages.part.28+0x1a\/0x22
[    0.000000] [<ffffffe0000056da>] __free_pages_bootmem+0x86\/0x90
[    0.000000] [<ffffffe000007c46>] free_all_bootmem+0x156\/0x1ba
[    0.000000] [<ffffffe0000023f8>] mem_init+0x36\/0x44
[    0.000000] [<ffffffe0000007a0>] start_kernel+0x1aa\/0x328
[    0.000000] [<ffffffe000000058>] _sinittext+0x58\/0x5c
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bfa
[    0.000000] страница:ffffffe03f029eb0 брой:0 mapcount:-65280 mapping:0000000000000000 index:0x0
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f0200b8 ffffffe03f0200b8 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] страницата е разтоварена, защото: ненулев mapcount
[    0.000000] Свързани модули:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Замърсено: G    B             4.19.0-sifive-1+ #1
[    0.000000] Обаждане на трасето:
[    0.000000] [<ffffffe00002cfde>] walk_stackframe+0x0\/0xa0
[    0.000000] [<ffffffe00002d1da>] show_stack+0x2a\/0x34
[    0.000000] [<ffffffe00063c898>] chachachllachachachTradeonachachach_inachachipachachachachllachachachTradeonachachachdevachachachypachachachllachachachTradeona+0x20\/0x28
[    0.000000] [<ffffffe00009499c>] bad_page+0xe4\/0x102
[    0.000000] [<ffffffe0000949f2>] free_pages_check_bad+0x38\/0x7a
[    0.000000] [<ffffffe0000955c6>] __free_pages_ok+0x3fe\/0x430
[    0.000000] [<ffffffe0000960ea>] __free_pages.part.28+0x1a\/0x22
[    0.000000] [<ffffffe0000056da>] __free_pages_bootmem+0x86\/0x90
[    0.000000] [<ffffffe000007c46>] free_all_bootmem+0x156\/0x1ba
[    0.000000] [<ffffffe0000023f8>] mem_init+0x36\/0x44
[    0.000000] [<ffffffe0000007a0>] start_kernel+0x1aa\/0x328
[    0.000000] [<ffffffe000000058>] _sinittext+0x58\/0x5c
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bfb
[    0.000000] страница:ffffffe03f029ee8 брой:0 mapcount:-65280 mapping:0000000000000000 index:0x0
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f0200f0 ffffffe03f0200f0 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] страницата е разтоварена, защото: ненулев mapcount
[    0.000000] Свързани модули:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Замърсено: G    B             4.19.0-sifive-1+ #1
[    0.000000] Обаждане на трасето:
[    0.000000] [<ffffffe00002cfde>] walk_stackframe+0x0\/0xa0
[    0.000000] [<ffffffe00002d1da>] show_stack+0x2a\/0x34
[    0.000000] [<ffffffe00063c898>] chachachllachachachTradeonachachach_inachachipachachachachllachachachTradeonachachachdevachachachypachachachllachachachTradeona+0x20\/0x28
[    0.000000] [<ffffffe00009499c>] bad_page+0xe4\/0x102
[    0.000000] [<ffffffe0000949f2>] free_pages_check_bad+0x38\/0x7a
[    0.000000] [<ffffffe0000955c6>] __free_pages_ok+0x3fe\/0x430
[    0.000000] [<ffffffe0000960ea>] __free_pages.part.28+0x1a\/0x22
[    0.000000] [<ffffffe0000056da>] __free_pages_bootmem+0x86\/0x90
[    0.000000] [<ffffffe000007c46>] free_all_bootmem+0x156\/0x1ba
[    0.000000] [<ffffffe0000023f8>] mem_init+0x36\/0x44
[    0.000000] [<ffffffe0000007a0>] start_kernel+0x1aa\/0x328
[    0.000000] [<ffffffe000000058>] _sinittext+0x58\/0x5c
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bfc
[    0.000000] страница:ffffffe03f029f20 брой:0 mapcount:-65280 mapping:0000000000000000 index:0x0
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f020028 ffffffe03f020028 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
...

Учудващо е, че след всичкото отстраняване на грешки реших да видя как трябва да изглежда 'референтният' изход на ядрото, казах make qemu, и видях подобна грешка.

За съжаление, следващото ниво (Linux kernel) е по-сложно: GDB, свързан чрез JTAG към RocketChip, работи, очевидно, с физически адреси, независимо от това как е конфигурирано MMU, а ядрото в момента, който ни интересува, вече е настроило отразяването на адресите, затова просто да кажем display/10i $pc не е възможно — ще видим само много unimp. Но, ако вече сме разбрали.offset (изглежда, че 0x80200000 -> 0xffffffe000000000), можем да действаме хитро:

1: x/10i $pc
=> 0xffffffe000002436 :      unimp
   0xffffffe000002438 :    unimp
   0xffffffe00000243a :    unimp
   0xffffffe00000243c :    unimp
   0xffffffe00000243e :    unimp
   0xffffffe000002440 :   unimp
   0xffffffe000002442 :   unimp
   0xffffffe000002444 :   unimp
   0xffffffe000002446 :   unimp
   0xffffffe000002448 :   unimp
(gdb) undisplay 1
(gdb) display/10i ($pc - 0xffffffe000002436 + 0x80202436)
2: x/10i ($pc - 0xffffffe000002436 + 0x80202436)
   0x80202436:  addi    sp,sp,-96
   0x80202438:  sd      s0,80(sp)
   0x8020243a:  sd      s1,72(sp)
   0x8020243c:  sd      s2,64(sp)
   0x8020243e:  sd      s3,56(sp)
   0x80202440:  sd      s4,48(sp)
   0x80202442:  sd      s5,40(sp)
   0x80202444:  sd      s6,32(sp)
   0x80202446:  sd      s7,24(sp)
   0x80202448:  sd      s8,16(sp)

Точките за прекъсване се поставят по подобен начин:

(gdb) p setup_smp
$1 = {} 0xffffffe000002436 
(gdb) b *0x80202436
Breakpoint 1 at 0x80202436
(gdb) c
Продължаване.

Програмата получи сигнал SIGTRAP, капан за трасировка/прекъсване.
setup_smp () at /home/trosinenko/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:58
58              while ((dn = of_find_node_by_type(dn, "cpu"))) {
(gdb) bt
#0  setup_smp () at /home/trosinenko/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:58
#1  0xffffffe0000022a2 in setup_arch () at /home/trosinenko/freedom-u-sdk/linux/arch/riscv/kernel/setup.c:253
#2  0x0000000000000000 in ?? ()
Backtrace stopped: frame did not save the PC

Само че трябва ръчно да ги премахнете, за да продължите — за GDB това е някакъв абсолютно неразбираем trap. Ах да, ако случайно кажете s или n вместо si, gdb ще се опита да встави неявна точка за прекъсване, която по разбираеми причини няма да бъде поставена, но и да разубедите GDB вече не е възможно. Но не бързайте да рестартирате дъската — по моите наблюдения, достатъчно е да рестартирате само gdb (имайте предвид, че старите точки за прекъсване може би няма да изчезнат).

Всъщност, ще трябва да се занимаваме с първоначалния проблем: разпределението на отладъчните printk в функция of_find_node_by_type, използваният код за търсене на зареждащото процесорно ядро, показва, че вижда някакъв боклук вместо имена на типове устройства. Например, откъде ли не взима реда «Serial port», въпреки че такъв явно няма в dtb в полето device_type. Търсейки тези байтове в образа на ядрото, ги намерих, погледнах на офсет и разбрах очевидното: размерът на ядрото в параметрите за зареждане явно е недооценен: отделени са 8Mb, а заема повече от десет. Отделих 16Mb, но странностите не спряха. След игра с четене на FDT от различни адреси (нормално адресът се предава на ядрото в регистъра a1), накрая реших да проследя какво точно в момента се парсира. За щастие, вместо да обикалям с дебъгер (а помним, че има нюанси с транслацията на адреси, които все още трябва да се решат), просто и по-грубо в файла drivers/of/fdt.c да се посочи #define pr_debug printk. В крайна сметка се получи:

добавяне на отладъчен изход

diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 3db0d71d128b..fac47df9d1db 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -173,6 +173,7 @@ asmlinkage void __init setup_vm(void)

 void __init parse_dtb(unsigned int hartid, void *dtb)
 {
+ printk("HART = %u DTB = %lxn", hartid, dtb);
 early_init_dt_scan(__va(dtb));
 }

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 74eaedd5b860..c019e4158e1d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -940,10 +940,12 @@ struct device_node *of_find_node_by_type(struct device_node *from,
 unsigned long flags;

 raw_spin_lock_irqsave(&devtree_lock, flags);
- for_each_of_allnodes_from(from, np)
+ for_each_of_allnodes_from(from, np) {
+ printk("%lx %lx [%s] | [%s]n", from, np, np->type, type);
 if (np->type && (of_node_cmp(np->type, type) == 0)
 && of_node_get(np))
 break;
+ }
 of_node_put(from);
 raw_spin_unlock_irqrestore(&devtree_lock, flags);
 return np;
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 800ad252cf9c..2b45870ebada 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -31,6 +31,8 @@

 #include "of_private.h"

+#define pr_debug printk
+
 /*
  * of_fdt_limit_memory - ограничава броя на регионите в възела /memory
  * @limit: максимален брой записи
@@ -1253,6 +1255,7 @@ bool __init early_init_dt_scan(void *params)
 */
 void __init unflatten_device_tree(void)
 {
+ printk("INITIAL: %lxn", initial_boot_params);
 __unflatten_device_tree(initial_boot_params, NULL, &of_root,
 early_init_dt_alloc_memory_arch, false);

Изход на хардуера

                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
 {
  #address-cells = ;
  #size-cells = ;
  compatible = "freechips,rocketchip-unknown-dev";
  model = "freechips,rocketchip-unknown";
  chosen {
    linux,initrd-start = ;
    riscv,kernel-end = ;
    riscv,kernel-start = ;
    #address-cells = ;
    #size-cells = ;
    bootargs = ;
  }
  firmware {
    sifive,uboot = "YYYY-MM-DD";
  }
  aliases {
    serial0 = ;
  }
  cpus {
    #address-cells = ;
    #size-cells = ;
    cpu@0 {
      device_type = "cpu";
      clock-frequency = ;
      compatible = "sifive,rocket0", "riscv";
      d-cache-block-size = ;
      d-cache-sets = ;
      d-cache-size = ;
      d-tlb-sets = ;
      d-tlb-size = ;
      i-cache-block-size = ;
      i-cache-sets = ;
      i-cache-size = ;
      i-tlb-sets = ;
      i-tlb-size = ;
      mmu-type = "riscv,sv39";
      next-level-cache = ;
      reg = ;
      riscv,isa = "rv64imafdc";
      status = "okay";
      timebase-frequency = ;
      tlb-split;
      interrupt-controller {
        #interrupt-cells = ;
        compatible = "riscv,cpu-intc";
        interrupt-controller;
        phandle = ;
      }
    }
  }
  ram@80000000 {
    device_type = "memory";
    reg = ;
    reg-names = "mem";
    phandle = ;
  }
  soc {
    #address-cells = ;
    #size-cells = ;
    compatible = "freechips,rocketchip-unknown-soc", "simple-bus";
    ranges;
    clint@2000000 {
      compatible = "riscv,clint0";
      interrupts-extended = ;
      reg = ;
      reg-names = "control";
    }
    debug-controller@0 {
      compatible = "sifive,debug-013", "riscv,debug-013";
      interrupts-extended = ;
      reg = ;
      reg-names = "control";
    }
    gpio@64002000 {
      #gpio-cells = ;
      #interrupt-cells = ;
      compatible = "sifive,gpio0";
      gpio-controller;
      interrupt-controller;
      interrupt-parent = ;
      interrupts = ;
      reg = ;
      reg-names = "control";
    }
    interrupt-controller@c000000 {
      #interrupt-cells = ;
      compatible = "riscv,plic0";
      interrupt-controller;
      interrupts-extended = ;
      reg = ;
      reg-names = "control";
      riscv,max-priority = ;
      riscv,ndev = ;
      phandle = ;
    }
    rom@10000 {
      compatible = "sifive,maskrom0";
      reg = ;
      reg-names = "mem";
    }
    serial@64000000 {
      compatible = "sifive,uart0";
      interrupt-parent = ;
      interrupts = ;
      reg = ;
      reg-names = "control";
    }
    spi@64001000 {
      #address-cells = ;
      #size-cells = ;
      compatible = "sifive,spi0";
      interrupt-parent = ;
      interrupts = ;
      reg = ;
      reg-names = "control";
      mmc@0 {
        compatible = "mmc-spi-slot";
        disable-wp;
        reg = ;
        spi-max-frequency = ;
        voltage-ranges = ;
      }
    }
    tlclk {
      #clock-cells = ;
      clock-frequency = ;
      clock-output-names = "tlclk";
      compatible = "fixed-clock";
    }
  }
}
[    0.000000] HART = 0 DTB = 81200000
[    0.000000] search "chosen", depth: 0, uname:
[    0.000000] search "chosen", depth: 1, uname: chosen
[    0.000000] Looking for initrd properties...
[    0.000000] Command line is: debug console=ttySIF0,125200 root=/dev/mmcblk0p2 loglevel=7 rootwait
[    0.000000] dt_root_size_cells = 1
[    0.000000] dt_root_addr_cells = 1
[    0.000000] memory scan node ram@80000000, reg size 8,
[    0.000000]  - 80000000 ,  40000000
[    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 Sat Jul 6 12:14:41 MSK 2019
[    0.000000] bootconsole [early0] enabled
[    0.000000] initrd not found or empty - disabling initrd
[    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] INITIAL: ffffffe001000000
[    0.000000]  -> unflatten_device_tree()
[    0.000000] Unflattening device tree:
[    0.000000] magic: d00dfeed
[    0.000000] size: 00001000
[    0.000000] version: 00000011
[    0.000000]   size is 13512, allocating...
[    0.000000]   unflattening (____ptrval____)...
[    0.000000] fixed up name for  ->
[    0.000000] fixed up name for chosen -> chosen
[    0.000000] fixed up name for firmware -> firmware
[    0.000000] fixed up name for aliases -> aliases
[    0.000000] fixed up name for cpus -> cpus
[    0.000000] fixed up name for cpu@0 -> cpu
[    0.000000] fixed up name for interrupt-controller -> interrupt-controller
[    0.000000] fixed up name for ram@80000000 -> ram
[    0.000000] fixed up name for soc -> soc
[    0.000000] fixed up name for clint@2000000 -> clint
[    0.000000] fixed up name for debug-controller@0 -> debug-controller
[    0.000000] fixed up name for gpio@64002000 -> gpio
[    0.000000] fixed up name for interrupt-controller@c000000 -> interrupt-controller
[    0.000000] fixed up name for rom@10000 -> rom
[    0.000000] fixed up name for serial@64000000 -> serial
[    0.000000] fixed up name for spi@64001000 -> spi
[    0.000000] fixed up name for mmc@0 -> mmc
[    0.000000] fixed up name for tlclk -> tlclk
[    0.000000]  <- unflatten_device_tree()
[    0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] 0 ffffffe03effcab0 [attach() failed for %s with error %d
[    0.000000] ] | [cpu]
[    0.000000] 0 ffffffe03eff0020 [(null)] | [cpu]

Изход в QEMU

                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
 {
  #address-cells = ;
  #size-cells = ;
  compatible = "riscv-virtio";
  model = "riscv-virtio,qemu";
  chosen {
    linux,initrd-start = ;
    linux,initrd-end = ;
    riscv,kernel-start = ;
    riscv,kernel-end = ;
    bootargs = "";
    stdout-path = ;
  }
  uart@10000000 {
    interrupts = ;
    interrupt-parent = ;
    clock-frequency = ;
    reg = ;
    compatible = "ns16550a";
  }
  test@100000 {
    reg = ;
    compatible = "sifive,test0";
  }
  virtio_mmio@10008000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10007000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10006000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10005000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10004000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10003000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10002000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  virtio_mmio@10001000 {
    interrupts = ;
    interrupt-parent = ;
    reg = ;
    compatible = "virtio,mmio";
  }
  cpus {
    #address-cells = ;
    #size-cells = ;
    timebase-frequency = ;
    cpu@0 {
      device_type = "cpu";
      reg = ;
      status = "okay";
      compatible = "riscv";
      riscv,isa = "rv64imafdcsu";
      mmu-type = "riscv,sv48";
      clock-frequency = ;
      interrupt-controller {
        #interrupt-cells = ;
        interrupt-controller;
        compatible = "riscv,cpu-intc";
        linux,phandle = ;
        phandle = ;
      }
    }
  }
  memory@80000000 {
    device_type = "memory";
    reg = ;
  }
  soc {
    #address-cells = ;
    #size-cells = ;
    compatible = "simple-bus";
    ranges;
    pci@30000000 {
      interrupt-map-mask = ;
      interrupt-map = ;
      ranges = ;
      reg = ;
      dma-coherent;
      bus-range = ;
      linux,pci-domain = ;
      device_type = "pci";
      compatible = "pci-host-ecam-generic";
      #size-cells = ;
      #interrupt-cells = ;
      #address-cells = ;
    }
    interrupt-controller@c000000 {
      linux,phandle = ;
      phandle = ;
      riscv,ndev = ;
      riscv,max-priority = ;
      reg-names = "control";
      reg = ;
      interrupts-extended = ;
      interrupt-controller;
      compatible = "riscv,plic0";
      #interrupt-cells = ;
      #address-cells = ;
    }
    clint@2000000 {
      interrupts-extended = ;
      reg = ;
      compatible = "riscv,clint0";
    }
  }
}
[    0.000000] HART = 0 DTB = 80e00000
[    0.000000] search "chosen", depth: 0, uname:
[    0.000000] search "chosen", depth: 1, uname: chosen
[    0.000000] Looking for initrd properties...
[    0.000000] initrd_start=0x88000000  initrd_end=0x88442b86
[    0.000000] Command line is: earlyprintk
[    0.000000] dt_root_size_cells = 2
[    0.000000] dt_root_addr_cells = 2
[    0.000000] memory scan node memory@80000000, reg size 16,
[    0.000000]  - 80000000 ,  40000000
[    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 Sat Jul 6 12:14:41 MSK 2019
[    0.000000] bootconsole [early0] enabled
[    0.000000] Initial ramdisk at: 0x(____ptrval____) (4467590 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] INITIAL: ffffffe000c00000
[    0.000000]  -> unflatten_device_tree()
[    0.000000] Unflattening device tree:
[    0.000000] magic: d00dfeed
[    0.000000] size: 00000d56
[    0.000000] version: 00000011
[    0.000000]   size is 14192, allocating...
[    0.000000]   unflattening (____ptrval____)...
[    0.000000] fixed up name for  ->
[    0.000000] fixed up name for chosen -> chosen
[    0.000000] fixed up name for uart@10000000 -> uart
[    0.000000] fixed up name for test@100000 -> test
[    0.000000] fixed up name for virtio_mmio@10008000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10007000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10006000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10005000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10004000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10003000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10002000 -> virtio_mmio
[    0.000000] fixed up name for virtio_mmio@10001000 -> virtio_mmio
[    0.000000] fixed up name for cpus -> cpus
[    0.000000] fixed up name for cpu@0 -> cpu
[    0.000000] fixed up name for interrupt-controller -> interrupt-controller
[    0.000000] fixed up name for memory@80000000 -> memory
[    0.000000] fixed up name for soc -> soc
[    0.000000] fixed up name for pci@30000000 -> pci
[    0.000000] fixed up name for interrupt-controller@c000000 -> interrupt-controller
[    0.000000] fixed up name for clint@2000000 -> clint
[    0.000000]  <- unflatten_device_tree()
[    0.000000] software IO TLB: mapped [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] 0 ffffffe03effc808 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effca78 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effcd98 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd068 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd230 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd4b8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd740 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd9c8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effdc50 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effded8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe160 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe3e8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe670 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe888 [cpu] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03effec00 [<NULL>] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03effeee8 [memory] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03efff0b0 [<NULL>] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03efff320 [pci] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03efff858 [<NULL>] | [cpu]
[    0.000000] ffffffe03effe888 ffffffe03efffd58 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effc808 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effca78 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effcd98 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd068 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd230 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd4b8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd740 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effd9c8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effdc50 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effded8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe160 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe3e8 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe670 [<NULL>] | [cpu]
[    0.000000] 0 ffffffe03effe888 [cpu] | [cpu]
[    0.000000] elf_hwcap is 0x112d
[    0.000000] percpu: Embedded 17 pages/cpu @(____ptrval____) s29400 r8192 d32040 u69632
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 258055
[    0.000000] Kernel command line: earlyprintk
[    0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
[    0.000000] Sorting __ex_table...
[    0.000000] Memory: 949716K/1046528K available (6565K kernel code, 342K rwdata, 2564K rodata, 208K init, 832K bss, 96812K reserved, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu:     RCU event tracing is enabled.
[    0.000000] rcu:     RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=1.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.000000] NR_IRQS: 0, nr_irqs: 0, preallocated irqs: 0
[    0.000000] plic: mapped 53 interrupts to 2 (out of 2) handlers.
[    0.000000] clocksource: riscv_clocksource: mask: 0xffffffffffffffff max_cycles: 0x24e6a1710, max_idle_ns: 440795202120 ns
[    0.000000] Console: colour dummy device 80x25
[    0.000000] console [tty0] enabled
[    0.000000] bootconsole [early0] disabled
[    0.000000] Calibrating delay loop (skipped), value calculated using timer frequency.. 20.00 BogoMIPS (lpj=100000)
[    0.000000] pid_max: default: 32768 minimum: 301
[    0.000000] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
[    0.000000] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
[    0.020000] rcu: Hierarchical SRCU implementation.
[    0.020000] smp: Bringing up secondary CPUs ...
[    0.020000] smp: Brought up 1 node, 1 CPU
[    0.050000] devtmpfs: initialized
[    0.050000] 0 ffffffe03effc808 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effca78 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effcd98 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effd068 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effd230 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effd4b8 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effd740 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effd9c8 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effdc50 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effded8 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effe160 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effe3e8 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effe670 [<NULL>] | [cpu]
[    0.050000] 0 ffffffe03effe888 [cpu] | [cpu]
[    0.050000] random: get_random_u32 called from bucket_table_alloc+0x76/0x17a with crng_init=0
[    0.050000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.050000] futex hash table entries: 256 (order: 2, 16384 bytes)
[    0.060000] NET: Registered protocol family 16
[    0.090000] vgaarb: loaded
[    0.090000] SCSI subsystem initialized
[    0.090000] usbcore: registered new interface driver usbfs
[    0.090000] usbcore: registered new interface driver hub
[    0.090000] usbcore: registered new device driver usb
[    0.090000] pps_core: LinuxPPS API ver. 1 registered
[    0.090000] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.090000] PTP clock support registered
[    0.100000] Advanced Linux Sound Architecture Driver Initialized.
[    0.100000] clocksource: Switched to clocksource riscv_clocksource
[    0.110000] NET: Registered protocol family 2
[    0.110000] tcp_listen_portaddr_hash hash table entries: 512 (order: 1, 8192 bytes)
[    0.110000] TCP established hash table entries: 8192 (order: 4, 65536 bytes)
[    0.110000] TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
[    0.110000] TCP: Hash tables configured (established 8192 bind 8192)
[    0.110000] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.110000] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.110000] NET: Registered protocol family 1
[    0.120000] Unpacking initramfs...
[    0.590000] workingset: timestamp_bits=62 max_order=18 bucket_order=0
[    0.620000] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
[    0.620000] io scheduler noop registered
[    0.620000] io scheduler deadline registered
[    0.620000] io scheduler cfq registered (default)
[    0.620000] io scheduler mq-deadline registered
[    0.620000] io scheduler kyber registered
[    0.620000] shpchp: Standard Hot Plug PCI Controller Driver version: 0.4
[    0.690000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    0.690000] 10000000.uart: ttyS0 at MMIO 0x10000000 (irq = 10, base_baud = 230400) is a 16550A
[    0.720000] console [ttyS0] enabled
[    0.720000] [drm] radeon kernel modesetting enabled.
[    0.720000] [drm] amdgpu kernel modesetting enabled.
[    0.730000] loop: module loaded
[    0.730000] libphy: Fixed MDIO Bus: probed
[    0.740000] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[    0.740000] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[    0.740000] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    0.740000] ehci-pci: EHCI PCI platform driver
[    0.740000] ehci-platform: EHCI generic platform driver
[    0.740000] mousedev: PS/2 mouse device common for all mice
[    0.740000] usbcore: registered new interface driver usbhid
[    0.740000] usbhid: USB HID core driver
[    0.740000] usbcore: registered new interface driver snd-usb-audio
[    0.740000] NET: Registered protocol family 10
[    0.750000] Segment Routing with IPv6
[    0.750000] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    0.750000] NET: Registered protocol family 17
[    0.750000] Key type dns_resolver registered
[    0.760000] ALSA device list:
[    0.760000]   No soundcards found.
[    0.770000] Freeing unused kernel memory: 208K
[    0.770000] This architecture does not have kernel memory protection.
[    0.770000] Run /init as init process

(«Таймстемпнутими» редове извежда ядрото, пред тях дървото извежда BBL) От една страна, FDT успешно се чете, от друга — получава се някаква глупост в разпарсното «обектно» дърво.

В процеса на отстраняване на грешки разбрах, че BBL не е могъл да прочете «двойния» адрес не защото в конфигурацията имаше грешка, а просто защото кореновият възел беше зададен. #address-cells = <1>; #size-cells = <1>;.

Разширявайки отладъчния изход, видях, че указателите на тип и name са «ударили», и то по доста странен начин: първият (започвайки от нула) байт се е обнулил, нещо като 0xabcdef -> 0xab00ef. Приходи се да се използва познатата тактика: знаейки адресите, на които се намира повредената памет, да допиша в функция printk печата на тези данни. И самите повиквания printk да разпръсна, където са малко. Уви, не стана много по-ясно. Тогава започнах, сверявайки се с дизасемблираната objdump версия, ръчно да поставям точки на спиране и стъпка по стъпка да преминавам през проблемната част от кода. И тук се откри загадъчно и неприятно: ако веднага поставя точка на спиране някъде относително далеч от known-good състояние, то, спирайки се на нея, ще видя вече повредена памет. Но ако се опитам тихо да се приближа до нея стъпка по стъпка, грешката успява да се скрие! Ситуацията воня на повреден контролер на паметта и кеш, който скрива грешката, ако постоянно запитвам нужната стойност. А какво ако…

Заменяме паметта.

Хванал се за възможността да реша проблема не на своя страна, предположих, че може би просто ми е попаднала повредена памет. Тук си спомних, че нетбукът от десетилетие е не само преносим компютър, но и ценен източник на DDR2 SO-DIMM. В допълнение, в него може да се постави извадената от дъската памет и да се получи практически мигновено замръзване в Memtest (Linux, между другото, при това се зарежда почти до графичната обвивка. Но по-добре не повтаряйте такъв експеримент, ако ви е скъпа информацията на монтираните дискове…). От една страна, може да се предположи, че просто паметта не е подходяща конкретно за този нетбук. От друга страна, той можа да се зареди! Появи се надежда, че просто паметта е «битата», и проблемът не е в моята обвивка.

Следователно, трябва да опитаме временно да стартираме с нетбук памет. За съжаление, Quartus 18 не може да обнови този IP Core така, че да бъде редактиран. Следователно, наистина е време да се научим да създаваме нови инстанции. Оказа се, че е доста просто: търсим в IP Catalog пункта DDR2 SDRAM Controller with ALTMEMPHY Intel FPGA IP и получаваме блок с такъв интерфейс, какъвто имаше преди. Единственият проблем е да зададем правилните настройки за паметта.

Получаваме параметрите на модул памет.

Има сравнително очевиден начин да настроим модула: да прочетем параметрите от SPD. Наистина, ако обикновеният компютър прочита данните SPD и настройва контролера според тях, нека прочетем тези данни на текущия нетбук и да ги въведем в таблицата.

На Ubuntu това става доста лесно.: трябва да инсталираме пакета i2c-tools, да заредим модулите eeprom и i2c-i801 (не съм сигурен, обаче, че вторият драйвер ще подхожда навсякъде), след което да стартираме decode-dimms.:

Изходът на decode-dimms

# decode-dimms version 6231 (2014-02-20 10:54:34 +0100)

Memory Serial Presence Detect Decoder
By Philip Edelbrock, Christian Zuckschwerdt, Burkart Lingner,
Jean Delvare, Trent Piepho and others

Decoding EEPROM: /sys/bus/i2c/drivers/eeprom/0-0050
Guessing DIMM is in                             bank 1

---=== SPD EEPROM Information ===---
EEPROM Checksum of bytes 0-62                   OK (0x00)
SPD Revision                                    Invalid
Fundamental Memory type                         Unknown (0x00)

---=== Manufacturing Information ===---
Manufacturer                                    Undefined
Part Number                                     Undefined

Decoding EEPROM: /sys/bus/i2c/drivers/eeprom/4-0050
Guessing DIMM is in                             bank 1

---=== SPD EEPROM Information ===---
EEPROM Checksum of bytes 0-62                   OK (0x00)
SPD Revision                                    Invalid
Fundamental Memory type                         Unknown (0x00)

---=== Manufacturing Information ===---
Manufacturer                                    Undefined
Part Number                                     Undefined

Decoding EEPROM: /sys/bus/i2c/drivers/eeprom/6-0050
Guessing DIMM is in                             bank 1

---=== SPD EEPROM Information ===---
EEPROM Checksum of bytes 0-62                   OK (0x76)
# of bytes written to SDRAM EEPROM              128
Total number of bytes in EEPROM                 256
Fundamental Memory type                         DDR2 SDRAM
SPD Revision                                    1.2

---=== Memory Characteristics ===---
Maximum module speed                            800 MHz (PC2-6400)
Size                                            1024 MB
Banks x Rows x Columns x Bits                   8 x 13 x 10 x 64
Ranks                                           2
SDRAM Device Width                              16 bits
Module Height                                   30.0 mm
Module Type                                     SO-DIMM (67.6 mm)
DRAM Package                                    Planar
Voltage Interface Level                         SSTL 1.8V
Module Configuration Type                       No Parity
Refresh Rate                                    Reduced (7.8 us) - Self Refresh
Supported Burst Lengths                         4, 8
tCL-tRCD-tRP-tRAS                               6-6-6-18
Supported CAS Latencies (tCL)                   6T, 5T, 4T
Minimum Cycle Time                              2.50 ns at CAS 6 (tCK min)
                                                3.00 ns at CAS 5
                                                3.75 ns at CAS 4
Maximum Access Time                             0.40 ns at CAS 6 (tAC)
                                                0.45 ns at CAS 5
                                                0.50 ns at CAS 4
Maximum Cycle Time (tCK max)                    8.00 ns

---=== Timing Parameters ===---
Address/Command Setup Time Before Clock (tIS)   0.17 ns
Address/Command Hold Time After Clock (tIH)     0.25 ns
Data Input Setup Time Before Strobe (tDS)       0.05 ns
Data Input Hold Time After Strobe (tDH)         0.12 ns
Minimum Row Precharge Delay (tRP)               15.00 ns
Minimum Row Active to Row Active Delay (tRRD)   10.00 ns
Minimum RAS# to CAS# Delay (tRCD)               15.00 ns
Minimum RAS# Pulse Width (tRAS)                 45.00 ns
Write Recovery Time (tWR)                       15.00 ns
Minimum Write to Read CMD Delay (tWTR)          7.50 ns
Minimum Read to Pre-charge CMD Delay (tRTP)     7.50 ns
Minimum Active to Auto-refresh Delay (tRC)      60.00 ns
Minimum Recovery Delay (tRFC)                   127.50 ns
Maximum DQS to DQ Skew (tDQSQ)                  0.20 ns
Maximum Read Data Hold Skew (tQHS)              0.30 ns

---=== Manufacturing Information ===---
Manufacturer                                    Samsung
Manufacturing Location Code                     0x02
Part Number                                     M4 70T2864QZ3-CF7
Revision Code                                   0x3351
Manufacturing Date                              2009-W34
Assembly Serial Number                          0x79C64E9A

Number of SDRAM DIMMs detected and decoded: 3

Проблемът е, че някои тайминги не са посочени тук, затова ще поемем по втория път.

Какво пише на модулите:

Част 4: Все пак стартираме Linux на RocketChip RISC-VЧаст 4: Все пак стартираме Linux на RocketChip RISC-V

В този случай по-интересен е надписът на самите микрочипове: K4T1G164QQ-HCF7. Въвеждайки този ред в Гугъл, получаваме datasheet на няколко десетки страници със всички необходими параметри, които може да запишете в свойствата на IP Core. Просто внимавайте за единиците за измерване: където има ns, а другаде — ps, а понякога дори и дроби tCK.Няма да ви уча какво да наблюдавате, много съм настроил по метода на опит и грешка (не мога да гарантирам, че така не можете да 'изгорите' паметта или FPGA). Ще обърна внимание само на следното: много дълго не можех да накарам контролера да работи и последната стъпка беше осъзнаването, че трябва да проверя ширината на всички интерфейси към паметта за съответствие с генерирания код на Verilog: защото когато в MemIfBundle е посочен val mem_ba = IO(Output(UInt(2.W))), а банките са 8 (т.е. адресът е с широчина 3 бита), всичко, което имаме — висящ в пространството output от контролера на паметта — е проблем, но не е критичен, затова всичко се синтезира, но не работи.

Възможно е всичко да се стартира и с стария модул, ако се обнови контролера, но засега ми е мързеливо да се занимавам с потенциални плаващи бъгове: и моите ми стигат.

И така, след преместването timebase-frequency в DTS от ниво конкретен CPU на ниво възел. cpus (при напълно ясна молба на ядрото), получаваме:

Скрит текст

[    0.000000] OF: fdt: Игнориране на диапазон памет 0x80000000 - 0x80200000
[    0.000000] Linux версия 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc версия 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Вт Jul 9 22:42:36 MSK 2019
[    0.000000] bootconsole [early0] активиран
[    0.000000] Начална ramdisk на: 0x(____ptrval____) (16777216 байта)
[    0.000000] Обхват на зоните:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Начало на подвижната зона за всеки възел
[    0.000000] Ранни диапазони на паметта на възела
[    0.000000]   възел   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Настройка на начален памет на възел 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] софтуерен IO TLB: картографиран [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] elf_hwcap е 0x112d
[    0.000000] percpu: Вградени 17 страници/ядро @(____ptrval____) s29400 r8192 d32040 u69632
[    0.000000] Изградени 1 zonelists, мобилност на групирането включена. Общо страници: 258055
[    0.000000] Команден ред на ядрото: debug console=ttySIF0,125200 root=\/dev\/mmcblk0p2 loglevel=7 rootwait
[    0.000000] Хеш таблица на кеша dentry: 131072 записа (поръчка: 8, 1048576 байта)
[    0.000000] Хеш таблица на кеша inode: 65536 записа (поръчка: 7, 524288 байта)
[    0.000000] Сортиране на __ex_table...
[    0.000000] Памет: 937696K\/1046528K налична (6565K код на ядрото, 343K rwdata, 2564K rodata, 208K init, 832K bss, 108832K запазена, 0K cma-reserved)
[    0.000000] SLUB: HWalign=64, Поръчка=0-3, MinObjects=0, Ядра=1, Възли=1
[    0.000000] rcu: Иерархична реализация на RCU.
[    0.000000] rcu:     проследяването на събитията RCU е активирано.
[    0.000000] rcu:     RCU ограничава ядра от NR_CPUS=8 до nr_cpu_ids=1.
[    0.000000] rcu: Настройка на геометрията за rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.000000] NR_IRQS: 0, nr_irqs: 0, предварително разпределени irqs: 0
[    0.000000] plic: картографирани 8 прекъсвания към 1 (от 2) обработвачи.
[    0.000000] source на часовника: riscv_clocksource: маска: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
[    0.000000] Конзола: цветно устройство dummy 80x25
[    0.000000] Калибриране на цикъла на забавяне (пропуснато), стойността изчислена с използване на честота на таймера.. 2.00 BogoMIPS (lpj=10000)
[    0.020000] pid_max: по подразбиране: 32768 минимално: 301
[    0.030000] Хеш таблица на кеша на монтиране: 2048 записа (поръчка: 2, 16384 байта)
[    0.040000] Хеш таблица на кеша на точката на монтиране: 2048 записа (поръчка: 2, 16384 байта)
[    0.140000] rcu: Иерархична реализация на SRCU.
[    0.190000] smp: Започване на вторични ядра ...
[    0.190000] smp: Включени 1 възел, 1 CPU
[    0.220000] devtmpfs: инициализирано
[    0.300000] random: get_random_u32 извикано от bucket_table_alloc+0x76\/0x17a с crng_init=0
[    0.330000] source на часовника: jiffies: маска: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.340000] хеш таблица на futex: 256 (поръчка: 2, 16384 байта)
[    0.380000] NET: Регистрирано семейство протоколи 16
[    1.850000] vgaarb: зареден
[    1.870000] Инициализация на подсистемата SCSI
[    1.900000] usbcore: регистриран нов интерфейсен драйвер usbfs
[    1.910000] usbcore: регистриран нов интерфейсен драйвер hub
[    1.920000] usbcore: регистриран нов интерфейсен драйвер usb
[    1.930000] pps_core: LinuxPPS API версия 1 регистрирана
[    1.940000] pps_core: Софтуерна версия 5.3.6 - Авторски права 2005-2007 Rodolfo Giometti 
[    1.950000] Поддръжка на PTP часовник регистрирана
[    1.970000] Услуга за звукова архитектура на Linux Инициализирана.
[    2.010000] source на часовника: Превключено към source на часовника riscv_clocksource
[    2.600000] NET: Регистрирано семейство протоколи 2
[    2.640000] tcp_listen_portaddr_hash хеш таблица записваща: 512 (поръчка: 1, 8192 байта)
[    2.650000] хеш таблица записи TCP established: 8192 (поръчка: 4, 65536 байта)
[    2.670000] хеш таблица записи TCP bind: 8192 (поръчка: 5, 131072 байта)
[    2.700000] TCP: Хеш таблиците настроени (установени 8192 свързването 8192)
[    2.720000] хеш таблица UDP: 512 (поръчка: 2, 16384 байта)
[    2.730000] хеш таблица UDP-Lite: 512 (поръчка: 2, 16384 байта)
[    2.750000] NET: Регистрирано семейство протоколи 1
[    2.770000] Разопаковане на initramfs...
[   23.980000] Разопаковането на initramfs не успя: боклук в компресирания архив
[   24.030000] workingset: timestamp_bits=62 max_order=18 bucket_order=0
[   25.020000] Устройство за SCSI генеричен блоков слой (bsg) версия 0.4 заредена (основна 251)
[   25.030000] io планировчик noop регистриран
[   25.040000] io планировчик deadline регистриран
[   25.050000] io планировчик cfq регистриран (по подразбиране)
[   25.060000] io планировчик mq-deadline регистриран
[   25.060000] io планировчик kyber регистриран
[   25.120000] sifive_gpio 64002000.gpio: SiFive GPIO чип регистриран 6 GPIOs
[   25.150000] shpchp: Стандартен драйвер за контролер PCI с гореща размяна версия: 0.4
[   28.870000] Serial: 8250\/16550 драйвер, 4 порта, IRQ споделянето е деактивирано
[   28.940000] sifive-serial 64000000.serial: не може да намери контролния часовник
[   28.950000] sifive-serial: проучването на 64000000.serial не успя с грешка -2
[   28.980000] [drm] radeon kernel modesetting включен.
[   28.990000] [drm] amdgpu kernel modesetting включен.
[   29.500000] loop: модулът е зареден
[   29.610000] sifive_spi 64001000.spi: Не може да намери тактовия сигнал на шина
[   29.620000] sifive_spi: проучването на 64001000.spi не успя с грешка -2
[   29.640000] libphy: Фиксиран MDIO Bus: проучен
[   29.680000] e1000e: Intel(R) PRO\/1000 Драйвер за мрежа - 3.2.6-k
[   29.690000] e1000e: Авторски права(c) 1999 - 2015 Intel Corporation.
[   29.700000] ehci_hcd: USB 2.0 'Разширен' Контролер на хост (EHCI) Драйвер
[   29.710000] ehci-pci: EHCI PCI платформен драйвер
[   29.720000] ehci-platform: EHCI генерален платформен драйвер
[   29.750000] mousedev: PS\/2 мишка устройство общо за всички мишки
[   29.790000] usbcore: регистриран нов интерфейсен драйвер usbhid
[   29.800000] usbhid: USB HID основен драйвер
[   29.820000] usbcore: регистриран нов интерфейсен драйвер snd-usb-audio
[   29.900000] NET: Регистрирано семейство протоколи 10
[   29.960000] Сегментно маршрутизиране с IPv6
[   29.960000] sit: Надслойване на IPv6, IPv4 и MPLS над IPv4
[   30.020000] NET: Регистрирано семейство протоколи 17
[   30.020000] Тип ключ dns_resolver регистриран
[   30.070000] bootconsole [early0] използва начална памет и трябва да бъде деактивирана дори преди реалната да е готова
[   30.080000] bootconsole [early0] деактивирана

След което няма видими промени.

Сега можем да опитаме да се справим с три проблема:

[   23.980000] Неуспех при разопаковане на Initramfs: боклук в компресиран архив
...
[   28.940000] sifive-serial 64000000.serial: не може да намери контролен часовник
...
[   29.610000] sifive_spi 64001000.spi: Не може да намери часовник на шина

… а също така с прекратяване на извеждането на конзолата.

С две проблеми с честотите не е много трудно да се справиш: нужно е да добавиш точки clocks в поддеревата на необходимите устройства, за удобство да се дава разбираемо име на етикета за възела tlclk:

diff --git a/arch/riscv/dts/zeowaa-1gb.dts b/arch/riscv/dts/zeowaa-1gb.dts
index 4b2cebc..1347e76 100644
--- a/arch/riscv/dts/zeowaa-1gb.dts
+++ b/arch/riscv/dts/zeowaa-1gb.dts
@@ -96,6 +97,7 @@
                 L8: serial@64000000 {
                         compatible = "sifive,uart0";
                         interrupt-parent = ;
+                        clocks = ;
                         interrupts = ;
                         reg = ;
                         reg-names = "control";
@@ -107,6 +109,7 @@
                         interrupt-parent = ;
                         interrupts = ;
                         reg = ;
+                        clocks = ;
                         reg-names = "control";
                         L12: mmc@0 {
                                 compatible = "mmc-spi-slot";
@@ -116,7 +119,7 @@
                                 voltage-ranges = ;
                         };
                 };
-                L11: tlclk {
+                tlclk: tlclk {
                         #clock-cells = ;
                         clock-frequency = ;
                         clock-output-names = "tlclk";

Добавяйки ред #define pr_debug printk в началото на файла init/initramfs.c, извеждащ съобщение за боклук вместо initramfs, получаваме малко по-подробно съобщение:

[    2.760000] Разопаковане на initramfs...
[    2.770000] Открито е компресирано с gzip данни
[   23.940000] Открито е (null) компресирано данни
[   23.970000] Неуспех при разопаковане на Initramfs: боклук в компресиран архив

Тоест, възможно е боклукът да не е вместо initramfs, а заедно.

Окей, нещо е открито, може и това да е достатъчно. А къде изчезна конзолата? Търсенето дава линк към проблема в GitHub: linux не успя да се стартира на платката vc707 — оказва се, че един UART не заслужава дори разговори според драйвера. Но поправка датата е 11 юли 2018 г. — година назад. Оказа се, че този комит не е попаднал в дървото, от което компилирам ядрото. След като приложих този пач ръчно, получих работещ Линукс! Оказа се, че проблемът с initramfs не е наистина критичен.

След като се логнах като user=root, password=sifive, успях без особени проблеми (освен да разбера, че номерът на GPIO има базова стойност, от която всичко се счита, и която просто трябва да се прочете от съответния псевдо-файл) да sysfs запаля светодиода на платката.

Както и преди, прилагам текстово видео за стартиране на Linux. В момента на превключване на конзолата от earlyprintk към стандартната излизат странни символи, които приличат на изход при неправилно зададена скорост на UART. Интересното е, че плейърът успешно е обработил тази "каша".

Част 4: Все пак стартираме Linux на RocketChip RISC-V

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster