Parte 4: Finalmente, executando o Linux no RocketChip RISC-V

Parte 4: Finalmente, executando o Linux no RocketChip RISC-V Na imagem, o kernel do Linux está te cumprimentando através do GPIO.

Nesta parte da história da portabilidade do RISC-V RocketChip para a placa chinesa com Cyclone IV, finalmente vamos executar o Linux, além de aprender a configurar o IP Core do controlador de memória e ajustar um pouco a descrição dts do hardware. Este artigo é uma continuação da terceira parte, mas, ao contrário da anterior, que era bastante extensa, esta será relativamente curta.

… Como setup_smp é chamado apenas se o kernel estiver configurado com suporte a SMP, podemos tentar desabilitar a multiprocessamento. Será desagradável se eu precisar implementar suporte à atomicidade no módulo de memória (eu achava que o cache lidava bem com isso), mas no caso de um único núcleo isso não deverá atrapalhar.

Ainda assim, não funcionou...

[    0.000000] OF: fdt: Ignorando a faixa de memória 0x80000000 - 0x80200000
[    0.000000] Versão do Linux 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc versão 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 Qui Jul 4 18:38:10 MSK 2019
[    0.000000] bootconsole [early0] habilitado
[    0.000000] Ramdisk inicial em: 0x(____ptrval____) (16777216 bytes)
[    0.000000] Faixas de zona:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Início da zona movível para cada nó
[    0.000000] Faixas de nós de memória inicial
[    0.000000]   nó   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Configuração de memória inicial nó 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] software IO TLB: mapeado [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] Não foi possível encontrar a entrada do dispositivo "cpu" da árvore de dispositivos
[    0.000000] Construiu 1 lista de zonas, agrupamento de mobilidade ativado. Total de páginas: 258055
[    0.000000] Linha de comando do kernel: debug console=ttySIF0,125200 root=\/dev\/mmcblk0p2 loglevel=7 rootwait
[    0.000000] Entradas na tabela de cache de diretórios: 131072 (ordem: 8, 1048576 bytes)
[    0.000000] Entradas na tabela de cache de inodes: 65536 (ordem: 7, 524288 bytes)
[    0.000000] Ordenando __ex_table...
[    0.000000] BUG: Estado de página ruim no processo swapper  pfn:80bf7
[    0.000000] página:ffffffe03f029e08 contagem:0 mapcount:-65280 mapeamento:0000000000000000 índice:0x1
[    0.000000] flags: 0x0()
[    0.000000] raw: 0000000000000000 0000000000000100 0000000000000200 0000000000000000
[    0.000000] raw: 0000000000000001 0000000000000000 00000000ffff00ff
[    0.000000] página despejada porque: mapcount não zero
[    0.000000] Módulos vinculados:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Não tingido 4.19.0-sifive-1+ #1
[    0.000000] Rastreio de chamadas:
[    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] Desabilitando a depuração de bloqueios devido à tingimento do kernel
[    0.000000] BUG: Estado de página ruim no processo swapper  pfn:80bf9
[    0.000000] página:ffffffe03f029e78 contagem:0 mapcount:-65280 mapeamento:0000000000000000 índice:0x0
[    0.000000] flags: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f020080 ffffffe03f020080 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] página despejada porque: mapcount não zero
[    0.000000] Módulos vinculados:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Tingido: G    B             4.19.0-sifive-1+ #1
[    0.000000] Rastreio de chamadas:
[    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: Estado de página ruim no processo swapper  pfn:80bfa
[    0.000000] página:ffffffe03f029eb0 contagem:0 mapcount:-65280 mapeamento:0000000000000000 índice:0x0
[    0.000000] flags: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f0200b8 ffffffe03f0200b8 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] página despejada porque: mapcount não zero
[    0.000000] Módulos vinculados:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Tingido: G    B             4.19.0-sifive-1+ #1
[    0.000000] Rastreio de chamadas:
[    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: Estado de página ruim no processo swapper  pfn:80bfb
[    0.000000] página:ffffffe03f029ee8 contagem:0 mapcount:-65280 mapeamento:0000000000000000 índice:0x0
[    0.000000] flags: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f0200f0 ffffffe03f0200f0 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
[    0.000000] página despejada porque: mapcount não zero
[    0.000000] Módulos vinculados:
[    0.000000] CPU: 0 PID: 0 Comm: swapper Tingido: G    B             4.19.0-sifive-1+ #1
[    0.000000] Rastreio de chamadas:
[    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: Estado de página ruim no processo swapper  pfn:80bfc
[    0.000000] página:ffffffe03f029f20 contagem:0 mapcount:-65280 mapeamento:0000000000000000 índice:0x0
[    0.000000] flags: 0x0()
[    0.000000] raw: 0000000000000000 ffffffe03f020028 ffffffe03f020028 0000000000000000
[    0.000000] raw: 0000000000000000 0000000000000000 00000000ffff00ff
...

É interessante que, após toda a depuração, eu decidi ver como deveria parecer a saída "de referência" do núcleo, disse make qemu, e vi um erro semelhante.

Infelizmente, o próximo nível (Linux kernel) é mais complicado: o GDB, conectado via JTAG ao RocketChip, aparentemente funciona com endereços físicos, independentemente de como o MMU esteja configurado, e o núcleo, no momento que nos interessa, já configurou a mapeação de endereços, então simplesmente dizer display/10i $pc não vai funcionar — veremos apenas muitos unimp.No entanto, se já descobrimos o deslocamento (aparentemente, 0x80200000 -> 0xffffffe000000000), podemos enganar:

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)

Os breakpoints são colocados da mesma forma:

(gdb) p setup_smp
$1 = {} 0xffffffe000002436 
(gdb) b *0x80202436
Breakpoint 1 at 0x80202436
(gdb) c
Continuando.

Programa recebeu sinal SIGTRAP, armadilha de rastreamento/breakpoint.
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 interrompido: frame não salvou o PC

Só que eles têm que ser removidos manualmente para seguir em frente — para o GDB, isso é alguma armadilha completamente incompreensível. Ah sim, se você acidentalmente disser s ou n em vez de si, o gdb tenta inserir um breakpoint implícito, que por razões óbvias não será estabelecido, mas não há como persuadir o GDB a desistir. Mas não se apresse em reiniciar a placa — pelas minhas observações, basta reiniciar apenas o gdb (considerando que os breakpoints antigos podem não desaparecer).

Na verdade, será necessário lidar com o problema original: configuração dos pontos de depuração printk na função of_find_node_by_type, o código de busca do núcleo do processador de inicialização mostra que está vendo algum lixo ao invés dos nomes dos tipos de dispositivos. Por exemplo, ele obtém a linha "Serial port" de algum lugar, embora isso claramente não exista no dtb no campo tipo_do_dispositivo. Após procurar esses bytes na imagem do núcleo, eu os encontrei, olhei para o deslocamento e percebi algo óbvio: o tamanho do núcleo nos parâmetros de inicialização está claramente subestimado: está alocado 8Mb, mas ele ocupa mais de dez. Alocou 16Mb, mas as estranhezas não pararam. Depois de tentar ler o FDT a partir de diferentes endereços (normalmente o endereço é passado ao núcleo em um registrador a1), finalmente decidi traçar o que está sendo agora mesmo analisado. Felizmente, em vez de ficar rodando com um depurador (e sabemos que há nuances com a tradução de endereços que ainda precisam ser resolvidas de qualquer forma), posso simplesmente, embora de forma improvisada, no arquivo drivers/of/fdt.c especificar #define pr_debug printk. No final, resultou em:

adicionando a saída de depuração

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 - limita o número de regiões no nó /memory
  * @limit: entradas máximas
@@ -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);

Saída no hardware

                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]

Saída no 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

(«Timestamped» lines are output by the kernel, before which the tree outputs BBL) On one hand, FDT reads successfully, on the other hand, some nonsense appears in the parsed "object" tree.

During debugging, I realized that BBL could not read the "double" address not because there was an error in the config, but simply because the root node had been set. #address-cells = <1>; #size-cells = <1>;.

Expanding the debug output, I saw that the pointers tipo e nome had "collided" in quite a strange way: their first (starting from zero) byte was zeroed out, something like 0xabcdef -> 0xab00ef. I had to use a familiar tactic: knowing the addresses where the corrupted memory resides, I wrote a function printk to print this data. And to scatter the calls printk where there are few. Unfortunately, it didn't become much clearer. Then I started, comparing with the disassembled objdump version, to manually set breakpoints and step through the problematic code section. And here something mysterious and unpleasant was discovered: if I immediately set a breakpoint somewhere far from the known-good state, then, stopping there, I will already see corrupted memory. But if I try to sneak up to it step by step, the error hides itself! This smells like a damaged memory controller and a cache hiding the error if the required value is continuously requested. What if…

Replace the memory

Clinging to the possibility of solving the problem not on my end, I suggested that perhaps I just received a faulty memory stick. Then I recalled that the ten-year-old netbook — is not only a portable computer but also a valuable source of DDR2 SO-DIMM. As a bonus, you can insert the memory taken from the board, and get almost instant Memtest freeze (Linux, by the way, loaded almost to the graphical interface in the process. But better not to repeat such an experiment if your information on mounted disks is dear to you…). On one hand, it can be assumed that the memory simply did not fit this netbook. On the other hand, it managed to boot up! There was hope that the memory was simply "bad", and the problem was not with my wrapper.

Então, precisamos tentar iniciar temporariamente com a memória do netbook. Infelizmente, o Quartus 18 não consegue atualizar este IP Core de forma que possa ser editado. Portanto, chegou a hora de aprender a criar novas instâncias. Tudo acabou sendo bastante simples: procuramos no IP Catalog pelo item DDR2 SDRAM Controller with ALTMEMPHY Intel FPGA IP e obtemos um bloco com a mesma interface de antes. O único problema é configurar as definições de memória corretas.

Obtemos os parâmetros do módulo de memória

Há uma maneira relativamente óbvia de configurar o módulo: ler os parâmetros do SPD. De fato, se um computador comum lê os dados do SPD e configura o controlador com eles, vamos extrair esses dados do netbook disponível e inseri-los em uma tabela.

No Ubuntu, isso é feito de maneira bastante simples: precisamos instalar o pacote i2c-tools, carregar os módulos eeprom e i2c-i801 (não tenho certeza de que o segundo driver funciona em todo lugar), após o que devemos executar decode-dimms:

A saída do 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

O problema é que alguns tempos não estão especificados aqui, portanto vamos seguir pelo segundo caminho.

O que está escrito nos módulos:

Parte 4: Finalmente, executando o Linux no RocketChip RISC-VParte 4: Finalmente, executando o Linux no RocketChip RISC-V

Neste caso, a inscrição nos próprios chips de memória é mais interessante: K4T1G164QQ-HCF7. Ao buscar esta linha no Google, obtemos uma ficha técnica de várias dezenas de páginas com todos os parâmetros necessários, que podemos cuidadosamente transcrever nas propriedades do IP Core. Apenas preste atenção às unidades de medida: às vezes ns, às vezes — ps, e às vezes até frações tCK. Não vou ensinar você a prestar atenção ao que é importante — eu mesmo configurei muita coisa por tentativa e erro (não posso garantir que isso não possa 'queimar' a memória ou o FPGA). Mas vou apenas destacar o seguinte: eu demorei muito para fazer o controlador funcionar, e o passo final foi perceber que precisava verificar a largura de todas as interfaces de memória para corresponder ao código gerado em Verilog: afinal, quando em MemIfBundle ser listado val mem_ba = IO(Output(UInt(2.W))), e há 8 bancos (ou seja, a largura do endereço é de 3 bits), então tudo o que temos — um output pendente do controlador de memória — é um problema, mas não crítico, portanto tudo é sintetizado, mas não funciona.

Talvez tudo funcionasse com o módulo antigo, se atualizássemos o controlador, mas até agora estou relutante em lidar com potenciais bugs flutuantes: já tenho os meus.

Assim, após mover timebase-frequency do DTS do nível do CPU específico para o nível do nó cpus (por um pedido claramente expresso pelo núcleo), obtemos:

Texto oculto

[    0.000000] OF: fdt: Ignorando o intervalo de memória 0x80000000 - 0x80200000
[    0.000000] Versão do Linux 4.19.0-sifive-1+ (trosinenko@trosinenko-pc) (gcc versão 8.3.0 (Buildroot 2019.02-07449-g4eddd28f99)) #1 SMP Ter Jul 9 22:42:36 MSK 2019
[    0.000000] bootconsole [early0] habilitado
[    0.000000] Ramdisk inicial em: 0x(____ptrval____) (16777216 bytes)
[    0.000000] Faixas de zona:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000]   Normal   [mem 0x00000000c0000000-0x00000bffffffffff]
[    0.000000] Início da zona movível para cada nó
[    0.000000] Faixas de nós de memória inicial
[    0.000000]   nó   0: [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] Configuração da memória de inicialização do nó 0 [mem 0x0000000080200000-0x00000000bfffffff]
[    0.000000] TLB de IO de software: mapeado [mem 0xbb1fc000-0xbf1fc000] (64MB)
[    0.000000] elf_hwcap é 0x112d
[    0.000000] percpu: 17 páginas embutidas/CPU @(____ptrval____) s29400 r8192 d32040 u69632
[    0.000000] 1 listas de zonas construídas, agrupamento de mobilidade ativado. Total de páginas: 258055
[    0.000000] Linha de comando do kernel: debug console=ttySIF0,125200 root=\/dev\/mmcblk0p2 loglevel=7 rootwait
[    0.000000] Entradas da tabela de hash do cache de dentries: 131072 (ordem: 8, 1048576 bytes)
[    0.000000] Entradas da tabela de hash do cache de inodes: 65536 (ordem: 7, 524288 bytes)
[    0.000000] Ordenando __ex_table...
[    0.000000] Memória: 937696K\/1046528K disponível (6565K código do kernel, 343K rwdata, 2564K rodata, 208K init, 832K bss, 108832K reservado, 0K cma-reservado)
[    0.000000] SLUB: HWalign=64, Ordem=0-3, MinObjects=0, CPUs=1, Nós=1
[    0.000000] rcu: Implementação hierárquica de RCU.
[    0.000000] rcu:     Rastreamento de eventos RCU está habilitado.
[    0.000000] rcu:     RCU restringindo CPUs de NR_CPUS=8 para nr_cpu_ids=1.
[    0.000000] rcu: Ajustando geometria para rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.000000] NR_IRQS: 0, nr_irqs: 0, irqs pré-alocados: 0
[    0.000000] plic: mapeado 8 interrupções para 1 (de 2) manipuladores.
[    0.000000] fonte de clock: riscv_clocksource: máscara: 0xffffffffffffffff max_cycles: 0x1d854df40, max_idle_ns: 3526361616960 ns
[    0.000000] Console: dispositivo dummy colorido 80x25
[    0.000000] Calibrando o loop de atraso (pulada), valor calculado usando a frequência do relógio.. 2.00 BogoMIPS (lpj=10000)
[    0.020000] pid_max: padrão: 32768 mínimo: 301
[    0.030000] Entradas da tabela de hash do cache de montagem: 2048 (ordem: 2, 16384 bytes)
[    0.040000] Entradas da tabela de hash do cache de pontos de montagem: 2048 (ordem: 2, 16384 bytes)
[    0.140000] rcu: Implementação hierárquica de SRCU.
[    0.190000] smp: Elevando CPUs secundárias ...
[    0.190000] smp: 1 nó, 1 CPU elevado
[    0.220000] devtmpfs: inicializado
[    0.300000] aleatório: get_random_u32 chamado de bucket_table_alloc+0x76\/0x17a com crng_init=0
[    0.330000] fonte de clock: jiffies: máscara: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.340000] entradas da tabela de hash futex: 256 (ordem: 2, 16384 bytes)
[    0.380000] NET: Família de protocolo 16 registrada
[    1.850000] vgaarb: carregado
[    1.870000] Subsistema SCSI inicializado
[    1.900000] usbcore: novo driver de interface registrado usbfs
[    1.910000] usbcore: novo driver de interface registrado hub
[    1.920000] usbcore: novo driver de dispositivo registrado usb
[    1.930000] pps_core: API LinuxPPS ver. 1 registrada
[    1.940000] pps_core: Versão de software 5.3.6 - Direitos autorais 2005-2007 Rodolfo Giometti 
[    1.950000] Suporte a relógio PTP registrado
[    1.970000] Driver da Arquitetura de Som Avançada do Linux Inicializado.
[    2.010000] fonte de clock: Mudou para a fonte de clock riscv_clocksource
[    2.600000] NET: Família de protocolo 2 registrada
[    2.640000] hash da tabela tcp_listen_portaddr: 512 entradas (ordem: 1, 8192 bytes)
[    2.650000] entradas da tabela de hash estabelecida TCP: 8192 (ordem: 4, 65536 bytes)
[    2.670000] entradas da tabela de hash TCP bind: 8192 (ordem: 5, 131072 bytes)
[    2.700000] TCP: Tabelas de hash configuradas (estabelecidas 8192 bind 8192)
[    2.720000] entradas da tabela de hash UDP: 512 (ordem: 2, 16384 bytes)
[    2.730000] entradas da tabela de hash UDP-Lite: 512 (ordem: 2, 16384 bytes)
[    2.750000] NET: Família de protocolo 1 registrada
[    2.770000] Descompactando initramfs...
[   23.980000] Descompactação do initramfs falhou: lixo no arquivo compactado
[   24.030000] workingset: timestamp_bits=62 max_order=18 bucket_order=0
[   25.020000] Driver genérico SCSI da camada de bloco (bsg) versão 0.4 carregado (maior 251)
[   25.030000] escalonador de entradas noop registrado
[   25.040000] escalonador de entradas deadline registrado
[   25.050000] escalonador de entradas cfq registrado (padrão)
[   25.060000] escalonador de entradas mq-deadline registrado
[   25.060000] escalonador de entradas kyber registrado
[   25.120000] sifive_gpio 64002000.gpio: Chip GPIO SiFive registrado com 6 GPIOs
[   25.150000] shpchp: Driver Padrão de Controlador PCI Hot Plug versão: 0.4
[   28.870000] Serial: driver 8250/16550, 4 portas, compartilhamento de IRQ desabilitado
[   28.940000] sifive-serial 64000000.serial: incapaz de encontrar clock do controlador
[   28.950000] sifive-serial: falha ao sondar 64000000.serial com erro -2
[   28.980000] [drm] modos de configuração do núcleo radeon habilitados.
[   28.990000] [drm] modos de configuração do núcleo amdgpu habilitados.
[   29.500000] loop: módulo carregado
[   29.610000] sifive_spi 64001000.spi: Incapaz de encontrar clock do barramento
[   29.620000] sifive_spi: falha ao sondar 64001000.spi com erro -2
[   29.640000] libphy: Barramento MDIO Fixo: sondado
[   29.680000] e1000e: Driver de Rede Intel(R) PRO/1000 - 3.2.6-k
[   29.690000] e1000e: Direitos Autorais(c) 1999 - 2015 Intel Corporation.
[   29.700000] ehci_hcd: Controlador Host USB 2.0 'Melhorado' Driver EHCI
[   29.710000] ehci-pci: driver da plataforma EHCI PCI
[   29.720000] ehci-platform: driver de plataforma EHCI genérico
[   29.750000] mousedev: dispositivo de mouse PS/2 comum para todos os mouses
[   29.790000] usbcore: novo driver de interface registrado usbhid
[   29.800000] usbhid: driver de núcleo HID USB
[   29.820000] usbcore: novo driver de interface registrado snd-usb-audio
[   29.900000] NET: Família de protocolo 10 registrada
[   29.960000] Segment Routing com IPv6
[   29.960000] sit: driver de tunelamento IPv6, IPv4 e MPLS sobre IPv4
[   30.020000] NET: Família de protocolo 17 registrada
[   30.020000] Tipo de chave dns_resolver registrado
[   30.070000] bootconsole [early0] usa memória de inicialização e deve ser desabilitado mesmo antes que o verdadeiro esteja pronto
[   30.080000] bootconsole [early0] desabilitado

Após isso, nada visível acontece.

Agora é possível tentar lidar com três problemas:

[   23.980000] Falha na descompactação do Initramfs: lixo no arquivo comprimido
...
[   28.940000] sifive-serial 64000000.serial: não foi possível encontrar o clock do controlador
...
[   29.610000] sifive_spi 64001000.spi: Não foi possível encontrar o clock da bus

… e também com a interrupção da saída no console.

Lidar com dois problemas de frequência é bem simples: é preciso adicionar os itens clocks nas subárvores dos dispositivos necessários, para conveniência, dando um nome claro ao rótulo do nó 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 = <&L0>;
+                        clocks = <&tlclk>;
                         interrupts = <2>;
                         reg = <&0x64000000 0x1000>;
                         reg-names = "control";
@@ -107,6 +109,7 @@
                         interrupt-parent = <&L0>;
                         interrupts = <1>;
                         reg = <&0x64001000 0x1000>;
+                        clocks = <&tlclk>;
                         reg-names = "control";
                         L12: mmc@0 {
                                 compatible = "mmc-spi-slot";
@@ -116,7 +119,7 @@
                                 voltage-ranges = <&3300 &3300>;
                         };
                 };
-                L11: tlclk {
+                tlclk: tlclk {
                         #clock-cells = <&0>;
                         clock-frequency = <&25000000>;
                         clock-output-names = "tlclk";

Adicionando a linha #define pr_debug printk no início do arquivo init/initramfs.c, ao imprimir a mensagem sobre lixo em vez de initramfs, obtemos uma mensagem um pouco mais detalhada:

[    2.760000] Descompactando initramfs...
[    2.770000] Dados comprimidos gzip detectados
[   23.940000] Dados comprimidos (null) detectados
[   23.970000] Falha na descompactação do Initramfs: lixo no arquivo comprimido

Ou seja, talvez o lixo não seja em vez de initramfs, mas sim juntos.

Ok, ele encontrou alguma coisa, talvez isso seja suficiente. Mas onde foi parar o console? A pesquisa revela uma referência a um problema no GitHub: linux falhou ao inicializar na placa vc707 — parece que um UART, na opinião do driver, nem mesmo vale a pena discutir. Mas a correção datada de 11 de julho de 2018 — um ano atrás. Descobri que esse commit nunca chegou ao repositório do qual estou construindo o kernel. Aplicando manualmente esse patch, tive um Linux funcionando! Descobri que a questão com o initramfs era, de fato, não crítica.

Ao me logar como user=root, password=sifive, consegui, sem muitos problemas (exceto por entender que o número GPIO tem um base, a partir do qual tudo é calculado, e que precisa ser lido a partir do respectivo arquivo pseudo), através de sysfs acender um LED na placa.

Como da última vez, estou anexando o vídeo em texto sobre a inicialização do Linux. No momento em que a console muda de earlyprintk para o padrão, aparece algum tipo de lixo, parecido com a saída quando a velocidade do UART não está configurada corretamente. O interessante é que o reprodutor lidou bem com essa "bagunça".

Parte 4: Finalmente, executando o Linux no RocketChip RISC-V

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster