Част 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] Настройка на началната памет за възел 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] софтуерен IO TLB: картографиран [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] Невъзможно е да се намери "cpu" entry в устройството
[    0.000000] Построен 1 списък на зони, групирането на мобилност е активирано. Общо страници: 258055
[    0.000000] Ядрото на командния ред: debug console=ttySIF0,125200 root=\/dev\/mmcblk0p2 loglevel=7 rootwait
[    0.000000] Кеш таблица на дентритите: 131072 (ред: 8, 1048576 байта)
[    0.000000] Кеш таблица на инодите: 65536 (ред: 7, 524288 байта)
[    0.000000] Подреждане на __ex_table...
[    0.000000] BUG: Лошо състояние на страницата в процеса swapper  pfn:80bf7
[    0.000000] страница:ffffffe03f029e08 count:0 mapcount:-65280 mapping:0000000000000000 индекс: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 Команда: 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 count:0 mapcount:-65280 mapping:0000000000000000 индекс: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 Команда: 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 count:0 mapcount:-65280 mapping:0000000000000000 индекс: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 Команда: 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 count:0 mapcount:-65280 mapping:0000000000000000 индекс: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 Команда: 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 count:0 mapcount:-65280 mapping:0000000000000000 индекс:0x0
[    0.000000] флагове: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f020028 ffffffe03f020028 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
...

Интересно, что после всей отладки я решил посмотреть, как должен выглядеть «референсный» вывод ядра, сказал make qemu, и увидел аналогичную ошибку.

К сожалению, следующий уровень (ядро Linux) сложнее: GDB, подключённый через JTAG к RocketChip, функционирует с физическими адресами вне зависимости от настроек MMU, а ядро на интересующий нас момент уже настроило отображение адресов, поэтому просто сказать display/10i $pc не получится — увидим лишь много unimp. Зато, если мы уже выяснили смещение (похоже, что 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 () в /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 () в /home/trosinenko/freedom-u-sdk/linux/arch/riscv/kernel/smpboot.c:58
#1  0xffffffe0000022a2 в setup_arch () в /home/trosinenko/freedom-u-sdk/linux/arch/riscv/kernel/setup.c:253
#2  0x0000000000000000 в ?? ()
Дополнительные сведения прерваны: фрейм не сохранил PC

Вот только их придется отключать вручную, чтобы продвинуться дальше — для GDB это совершенно непонятная ловушка. Ах да, если вы случайно скажете 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 
[    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>;.

Разширявайки отстраняващия изход, видях, че указателите на тип и име «се сблъскаха» по доста странен начин: първият (счетено от нула) байт беше нулиран, нещо подобно на 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 Вт, 9 юли 2019 г. 22:42:36 MSK
[    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 списъка на зони, мобилността е активирана. Общо страници: 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-резервирани)
[    0.000000] SLUB: HWalign=64, Поръчка=0-3, MinObjects=0, CPUs=1, Възли=1
[    0.000000] rcu: Иерархична RCU реализация.
[    0.000000] rcu:     RCU проследяване на събития е активирано.
[    0.000000] rcu:     RCU ограничава CPUs от 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, предварителноalloцирани irq: 0
[    0.000000] plic: картографирани 8 прекъсвания на 1 (от 2) обработчици.
[    0.000000] clocksource: 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: Стартиране на вторични CPUs ...
[    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] clocksource: 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] clocksource: Превключено към clocksource riscv_clocksource
[    2.600000] NET: Регистрирано семейство протоколи 2
[    2.640000] tcp_listen_portaddr_hash хеш таблица записи: 512 (поръчка: 1, 8192 байта)
[    2.650000] TCP установени хеш таблица записи: 8192 (поръчка: 4, 65536 байта)
[    2.670000] TCP bind хеш таблица записи: 8192 (поръчка: 5, 131072 байта)
[    2.700000] TCP: Конфигурирани хеш таблици (установени 8192 bind 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 scheduler noop регистриран
[   25.040000] io scheduler deadline регистриран
[   25.050000] io scheduler cfq регистриран (по подразбиране)
[   25.060000] io scheduler mq-deadline регистриран
[   25.060000] io scheduler kyber регистриран
[   25.120000] sifive_gpio 64002000.gpio: SiFive GPIO чип регистриран 6 GPIO
[   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 режим на ядрото е активиран.
[   28.990000] [drm] amdgpu режим на ядрото е активиран.
[   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 {
                         съвместимо = "sifive,uart0";
                         interrupt-parent = <&L0>;
+                        clocks = <&tlclk>;
                         прекъсвания = <>;
                         рег = <>;
                         имена на рег = "контрол";
@@ -107,6 +109,7 @@
                         interrupt-parent = <&L0>;
                         прекъсвания = <>;
                         рег = <>;
+                        clocks = <&tlclk>;
                         имена на рег = "контрол";
                         L12: mmc@0 {
                                 съвместимо = "mmc-spi-slot";
@@ -116,7 +119,7 @@
                                 напрежение-домаин= <>;
                         };
                 };
-                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, а с тази, успяхме да изпращаме заявки по наш вкус, включително замяна на заглавия, метод на HTTP, параметри и данни, които kube-controller-manager след това обработваше..

Окей, нещо е намерил, може би, и това е достатъчно. А къде отиде конзолата? Търсенето дава връзка към проблема в GitHub: linux failed to bringup on vc707 board — оказва се, един 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