xHi*_*ire 5 arm u-boot linux-kernel cubieboard
I\xe2\x80\x99m 试图为 ARM 制作一个大端的 Linux 发行版。由于我在 Gentoo 上\xe2\x80\x99m,交叉编译再简单不过了。我\xe2\x80\x99已经构建了所有这些,但后来陷入了让它/内核启动的困境。
\n\nI\xe2\x80\x99m 针对采用 AllWinner A10 CPU 的 Cubieboard。我使用 u-boot 作为引导加载程序。由于 u-boot 不\xe2\x80\x99t 支持大端 ARM,因此我在将控制权传递给内核之前对其进行了修补:
\n\ndiff -Naur u-boot-2016.01-1/arch/arm/lib/bootm.c u-boot-2016.01-2/arch/arm/lib/bootm.c\n--- u-boot-2016.01-1/arch/arm/lib/bootm.c 2016-01-12 15:06:54.000000000 +0100\n+++ u-boot-2016.01-2/arch/arm/lib/bootm.c 2017-07-09 14:13:29.675865446 +0200\n@@ -315,7 +315,16 @@\n 0, machid, r2);\n } else\n #endif\n+ {\n+ {\n+ unsigned long v;\n+ __asm volatile ("mrc p15, 0, %0, c1, c0, 0\\n\\t"\n+ "orr %0, %0, #(1 << 7)\\n\\t" /* Switch to bigendian */\n+ "mcr p15, 0, %0, c1, c0, 0" : "=&r" (v));\n+ }\n+\n kernel_entry(0, machid, r2);\n+ }\n }\n #endif\n }\n
Run Code Online (Sandbox Code Playgroud)\n\n我最初使用了一些不同的语法,但最终从 APEX 引导加载程序(其arm-kernel-shim)中获取了已知可用的代码。(尽管如此,该寄存器与我拥有的以及我在 ARM 文档中读到的相同。)
\n\n另外,由于 u-boot 需要是小端,所以我为它准备了另一个工具链\xe2\x80\x94with target arm-linux-gnueabihf
。据我所知,u-boot 本身可以正常启动。
(主线)内核是使用 target 的工具链编译的armeb-linux-gnueabihf
。从编译后的映像(arch/arm/boot/Image
在内核源/构建树中),我构建了一个可启动映像(使用mkimage
我的 u-boot 构建):
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\n
Run Code Online (Sandbox Code Playgroud)\n\n我也从内核中获取了 DTB 文件:
\n\ncp /usr/armeb-linux-gnueabihf/usr/src/linux/arch/arm/boot/dts/sun4i-a10-cubieboard.dtb /usr/armeb-linux-gnueabihf/boot/\n
Run Code Online (Sandbox Code Playgroud)\n\n当我将其全部加载到 \xc2\xb5SD 卡并尝试启动时,我在串行控制台上得到以下输出:
\n\nU-Boot SPL 2016.01 (Jul 16 2017 - 13:52:00)\nDRAM: 1024 MiB\nCPU: 1008000000Hz, AXI/AHB/APB: 3/2/2\nTrying to boot from MMC\n\n\nU-Boot 2016.01 (Jul 16 2017 - 13:52:00 +0200) Allwinner Technology\n\nCPU: Allwinner A10 (SUN4I)\nI2C: ready\nDRAM: 1 GiB\nMMC: SUNXI SD/MMC: 0\nIn: serial\nOut: serial\nErr: serial\nSCSI: SUNXI SCSI INIT\nSATA link 0 timeout.\nAHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode\nflags: ncq stag pm led clo only pmp pio slum part ccc apst\nNet: eth0: ethernet@01c0b000\nstarting USB...\nUSB0: USB EHCI 1.00\nUSB1: USB OHCI 1.0\nUSB2: USB EHCI 1.00\nUSB3: USB OHCI 1.0\nscanning bus 0 for devices... 1 USB Device(s) found\nscanning bus 2 for devices... 1 USB Device(s) found\nHit any key to stop autoboot: 0\n=> 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\n=> ext2load mmc 0 0x48000000 boot/uimage\n5025856 bytes read in 592 ms (8.1 MiB/s)\n=> ext2load mmc 0 0x51000000 boot/sun4i-a10-cubieboard.dtb\n28542 bytes read in 237 ms (117.2 KiB/s)\n=> bootm 0x48000000 - 0x51000000\n## Booting kernel from Legacy Image at 48000000 ...\n Image Name: Linux-4.9.9-gentoo\n Image Type: ARM Linux Kernel Image (uncompressed)\n Data Size: 5025792 Bytes = 4.8 MiB\n Load Address: 48000000\n Entry Point: 48000000\n Verifying Checksum ... OK\n## Flattened Device Tree blob at 51000000\n Booting using the fdt blob at 0x51000000\n Loading Kernel Image ... OK\n Loading Device Tree to 49ff6000, end 49ffff7d ... OK\n\nStarting kernel ...\n
Run Code Online (Sandbox Code Playgroud)\n\n它只是挂在那里,像这样 \xe2\x80\x93 没有进度,没有输出,什么也没有。我的问题是,如何从这里开始/如何找出实际发生的情况?我错过了什么吗?我做错了什么吗(或者没有\xe2\x80\x99t 做了什么)?
\n\n我还尝试了一些但没有成功的事情:
\n\n对内核映像进行字交换(如 APEX 所做的那样)(导致undefined instruction
启动时),
使用压缩的内核映像,
使用旧版 FEX 文件而不是 FDT。
2017/07/21 更新:我\xe2\x80\x99已经部分成功地解决了我的问题。我从 Tom Rini\xe2\x80\x99s 评论中得到提示,并尝试将 zImage 打包到 uImage 中,从而使内核启动。通过自定义 init 程序(只是一个简单的 Hello World 编译的 BE 或 LE),我证实了 Tom Rini\xe2\x80\x99s 的另一个怀疑:我原来的内核不是大端,而是小端。为了解决这个问题,我将以下两行添加到 kernel\xe2\x80\x99s 的顶部.config
:
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y\nCONFIG_CPU_BIG_ENDIAN=y\n
Run Code Online (Sandbox Code Playgroud)\n\n我的灵感来自Nvidia Jetson TK1 的操作方法。arch/arm/mach-sunxi/Kconfig
我还在 A10 部分的末尾添加了以下行:
select ARCH_SUPPORTS_BIG_ENDIAN\n
Run Code Online (Sandbox Code Playgroud)\n\n事实证明,这足以构建和启动大端内核,因为内核本身会将 CPU 切换到大端模式。然而,它是通过setend
指令来实现的——它的范围仅适用于内核本身,而不适用于用户空间(如 Murray Jensen\xe2\x80\x99s 答案中的链接所解释)。
我\xe2\x80\x99m 要尝试:
\n\n通过异常跳转到 kernel\xe2\x80\x99s 解压器入口点,或者(如果我失败)
修补内核,使其将进程生成为大端设置(尽管我在那里闻到了雷区的味道......)。