Estou tentando fazer uma grande criação endian de uma distribuição do Linux para o ARM. Como estou no Gentoo, a compilação cruzada não poderia ser mais fácil. Eu já construí tudo, mas depois fiquei com a ideia de conseguir / o kernel inicializar.
Estou segmentando o Cubieboard com a CPU AllWinner A10. Como um bootloader eu uso o u-boot. Como o u-boot não suporta o big endian ARM, atualizei-o exatamente antes de passar o controle para o kernel:
diff -Naur u-boot-2016.01-1/arch/arm/lib/bootm.c u-boot-2016.01-2/arch/arm/lib/bootm.c
--- u-boot-2016.01-1/arch/arm/lib/bootm.c 2016-01-12 15:06:54.000000000 +0100
+++ u-boot-2016.01-2/arch/arm/lib/bootm.c 2017-07-09 14:13:29.675865446 +0200
@@ -315,7 +315,16 @@
0, machid, r2);
} else
#endif
+ {
+ {
+ unsigned long v;
+ __asm volatile ("mrc p15, 0, %0, c1, c0, 0\n\t"
+ "orr %0, %0, #(1 << 7)\n\t" /* Switch to bigendian */
+ "mcr p15, 0, %0, c1, c0, 0" : "=&r" (v));
+ }
+
kernel_entry(0, machid, r2);
+ }
}
#endif
}
Eu originalmente usei uma sintaxe um pouco diferente, mas no final peguei um código conhecido para o trabalho do gerenciador de inicialização APEX (seu arm-kernel-shim). (No entanto, o registro é o mesmo que eu e o que li na documentação do ARM.)
Além disso, como o u-boot precisa ser little endian, preparei outro conjunto de ferramentas para ele - com o destino arm-linux-gnueabihf
. Tanto quanto eu posso dizer, o próprio u-boot inicializa bem.
O kernel (principal) é compilado com um conjunto de ferramentas para o destino armeb-linux-gnueabihf
. A partir da imagem compilada ( arch/arm/boot/Image
dentro do kernel source / build tree) eu criei uma imagem inicializável (usando mkimage
da minha compilação de inicialização):
mkimage -C none -A arm -T kernel -n Linux-4.9.9-gentoo -d /usr/armeb-linux-gnueabihf/usr/src/linux/arch/arm/boot/Image -ep 0x48000000 -a 0x48000000 /usr/armeb-linux-gnueabihf/boot/uimage
Eu peguei o arquivo DTB também do kernel:
cp /usr/armeb-linux-gnueabihf/usr/src/linux/arch/arm/boot/dts/sun4i-a10-cubieboard.dtb /usr/armeb-linux-gnueabihf/boot/
Quando eu carrego tudo no cartão µSD e tento inicializar, recebo a seguinte saída no console serial:
U-Boot SPL 2016.01 (Jul 16 2017 - 13:52:00)
DRAM: 1024 MiB
CPU: 1008000000Hz, AXI/AHB/APB: 3/2/2
Trying to boot from MMC
U-Boot 2016.01 (Jul 16 2017 - 13:52:00 +0200) Allwinner Technology
CPU: Allwinner A10 (SUN4I)
I2C: ready
DRAM: 1 GiB
MMC: SUNXI SD/MMC: 0
In: serial
Out: serial
Err: serial
SCSI: SUNXI SCSI INIT
SATA link 0 timeout.
AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
flags: ncq stag pm led clo only pmp pio slum part ccc apst
Net: eth0: ethernet@01c0b000
starting USB...
USB0: USB EHCI 1.00
USB1: USB OHCI 1.0
USB2: USB EHCI 1.00
USB3: USB OHCI 1.0
scanning bus 0 for devices... 1 USB Device(s) found
scanning bus 2 for devices... 1 USB Device(s) found
Hit any key to stop autoboot: 0
=> setenv bootargs console=tty0 console=ttyS0,115200 earlyprintk hdmi.audio=EDID:0 disp.screen0_output_mode=EDID:1280x800p60 root=PARTUUID=AC9D6C6F-01 rootwait panic=10
=> ext2load mmc 0 0x48000000 boot/uimage
5025856 bytes read in 592 ms (8.1 MiB/s)
=> ext2load mmc 0 0x51000000 boot/sun4i-a10-cubieboard.dtb
28542 bytes read in 237 ms (117.2 KiB/s)
=> bootm 0x48000000 - 0x51000000
## Booting kernel from Legacy Image at 48000000 ...
Image Name: Linux-4.9.9-gentoo
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 5025792 Bytes = 4.8 MiB
Load Address: 48000000
Entry Point: 48000000
Verifying Checksum ... OK
## Flattened Device Tree blob at 51000000
Booting using the fdt blob at 0x51000000
Loading Kernel Image ... OK
Loading Device Tree to 49ff6000, end 49ffff7d ... OK
Starting kernel ...
E ele simplesmente fica parado assim - sem progresso, sem saída, sem nada. Minha pergunta é: como proceder daqui / como descobrir o que está realmente acontecendo? Estou faltando alguma coisa, fiz alguma coisa errada (ou não fiz algo)?
Mais algumas coisas que tentei, mas sem sucesso:
-
troca de palavras da imagem do kernel (como o APEX faz) (resultou em undefined instruction
na inicialização),
-
usando a imagem do kernel compactada,
-
usando o arquivo legado FEX em vez de FDT.
Atualização 2017/07/21: fui parcialmente bem-sucedido na solução do meu problema. Tomei a dica do comentário de Tom Rini e tentei compactar o zImage para a imagem que fez a inicialização do kernel. Com um programa init personalizado (apenas um simples Hello World compilado como BE ou LE), confirmei a suspeita do outro Tom Rini: meu kernel original não era grande, mas pouco. Para corrigir isso, adicionei as duas linhas a seguir ao início do .config
do kernel:
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
CONFIG_CPU_BIG_ENDIAN=y
Eu busquei minha inspiração de um como fazer para a Nvidia Jetson TK1 . Eu também adicionei a seguinte linha a arch/arm/mach-sunxi/Kconfig
no final da seção A10:
select ARCH_SUPPORTS_BIG_ENDIAN
Descobriu-se que isso é suficiente para construir e inicializar um kernel big endian, já que o próprio kernel muda a CPU para o modo big endian. No entanto, ele faz isso com a instrução setend
- seu escopo é apenas para o próprio kernel, não para o espaço do usuário (como explica o link na resposta de Murray Jensen).
Vou tentar:
-
ir para o ponto de entrada do descompactador do kernel por meio de exceção ou (se eu falhar)
-
remendando o kernel para que ele crie processos em grandes configurações de endian (apesar de eu sentir o cheiro de um campo minado lá ...).