Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ass:laboratoare:02:tasks:01 [2023/07/15 18:53]
radu.mantu
— (current)
Line 1: Line 1:
-==== 01. [??p] Preparing the Flattened μImage Tree ==== 
  
-There are three vital components that are required to successfully boot Linux on ARM: 
-  * **Kernel image:** This should be self-evident :p 
-  * **Flattened Device Tree:** A structured binary blob of data that the kernel parses to identify hardware elements. 
-  * **RootFS:** A file system that can be mounted at ''/''​ in order to load **init**. Here, we will use a ramdisk image. 
- 
-Although these components can be manually loaded and configured for boot from U-Boot, it's preferable to package them together in a Flattened μImage Tree (FIT). Similarly to how **bl1** and **bl2** know how to load the binaries that comprise the FIP we generated in the previous lab, **bl33** also knows how to boot the system from a FIT. 
- 
-In the following tasks we will create each individual component and package them together. Finally, we will create a partition table (with one FAT partition) on the board'​s eMMC and store the FIT only to then load it and boot it from the **bl33** shell. 
- 
-=== [??p] Task A - Linux kernel === 
- 
-Clone the kernel from the official github repo. Since you've built U-Boot previously, you should be somewhat familiar with the Kbuild system. Generate the default ARM configuration file and compile the kernel. 
- 
-Note that the kernel image you will be including in the FIP is called **Image**. Unlike **vmlinux** which is an ELF file (i.e.: contains useless sections, including //​.debuginfo//​ if you want to debug the kernel), **Image** is a boot executable image, made specifically for you to jump straight in and start executing. After the build process finalizes, **find** the **Image** file within the Linux repo. 
- 
-<note tip> 
-Paralellize the build process using ''​make -j'',​ unless you want to waste an hour for Linux to build. \\ 
-Do not forget about the ''​CROSS_COMPILE''​ argument. \\ 
-Set the ''​ARCH''​ argument to the appropriate architecture. Check out the subdirectories in ''​linux/​arch/''​ for possible values. 
-</​note>​ 
- 
-<note tip> 
-After you finish an initial build of the kernel, consider running the following script: 
- 
-<code bash> 
-./​scripts/​clang-tools/​gen_compile_commands.py 
-</​code>​ 
- 
-This will generate a ''​compile_commands.json''​ file that contains the **gcc** invocation cmdline. Any half decent language server will be able to (automatically) parse this file and deduce the include paths and definitions used. This will enable features like [[https://​neovim.io/​doc/​user/​lsp.html#​vim.lsp.buf.definition()|go-to-definition]] between different source files and much more. 
- 
-Note that this script only works on Linux. For a more generic tool, try [[https://​github.com/​rizsotto/​Bear|bear]]. Be warned though that its LD_PRELOAD hooking of ''​exec()''​ calls (needed to extract the cmdargs) interferes with the [[https://​www.gnu.org/​software/​automake/​|Automake]] configuration stage. 
-</​note>​ 
- 
-=== [??p] Task B - Flattened Device Tree === 
- 
-Luckily, the FDT for our platform is also included in Linux. It's name should be **imx8mq-pico-pi.dtb**. 
- 
-If for some reason it wasn't built alongside the kernel Image, check out the ''​dtbs''​ make target. 
- 
-=== [??p] Task C - Root Filesystem === 
- 
-Usually there are two approaches to generating the root filesystem: bootstrapping from a source of pre-compiled binaries (e.g.: [[https://​man.archlinux.org/​man/​debootstrap.8.en|debootstrap]],​ [[https://​man.archlinux.org/​man/​pacstrap.8|pacstrap]],​ etc.) or building them yourself (e.g.: [[https://​www.yoctoproject.org/​yocto|Yocto]],​ [[https://​buildroot.org/​|Buildroot]].) The former is usually preferred when working on desktop environments. The latter allows you to fine tune everything that is installed on your system. For example, the [[https://​wiki.archlinux.org/​title/​OpenSSH|OpenSSH]] package available via **pacstrap** will come with a default build of **sshd** (the SSH server). On some critical infrastructure however, you might want to harden the SSH server binary by using a custom dynamic loader instead of **ld-linux** which allows LD_PRELOAD hooks. 
- 
-Between Yocto and Buildroot, we generally opt for Buildroot. While Yocto has its advantages (e.g.: wide industry adoption, extensive device support, etc.), it also has a very steep learning curve and consumes significant amounts of resources (i.e.: ~50G storage space for a build). Although it has a layer-based build customization feature (think Dockerfiles extending base images), we argue that this makes it more difficult to comprehend the contents of what is being built. 
- 
-Buildroot on the other hand is geared towards simplicity and ease of use. Being based on Kbuild and Makefile (same as Linux and U-Boot) makes it instantly familiar to most developers. And even if you are new to this, while Yocto requires you to read entire [[https://​www.goodreads.com/​search?​q=yocto|books]] in order to utilize it properly, Buildroot can be summed up in a 1k LoC Makefile. 
- 
-== Step 1: Download Buildroot == 
- 
-Clone the official [[https://​github.com/​buildroot/​buildroot.git|Buildroot repo]]. 
- 
-== Step 2: Create the configuration == 
- 
-Find an existing defconfig for our platform (the **imx8mq**) and take a look at what it contains. Notice how the following config options are enabled: 
- 
-<​code>​ 
-BR2_LINUX_KERNEL=y 
-BR2_TARGET_ARM_TRUSTED_FIRMWARE=y 
-BR2_TARGET_UBOOT=y 
-</​code>​ 
- 
-Yes, Buildroot also integrates the bootloaders into its build system. However, keeping the components separate makes it easier to appply patches and debug problems. What we want from Buildroot is a minimal root filesystem and nothing more. So, after generating ''​.config'',​ enter ''​menuconfig''​ and make a few changes: 
-  * Disable all components that we've already integrated in our build environment (starting with the ones above). 
-  * Use an **external, custom, pre-installed toolchain**. 
-  * Use **systemd** as the init system instead of **BusyBox**. 
-  * Use **bash** as the default shell instead of **sh**. 
-  * Set //"​root"//​ as password for the root user. 
-  * Include a text editor package (e.g.: **vim** or **nano**). 
-  * Generate an **uncompressed CPIO** image from the output file system (see the Note below). 
- 
-<​note>​ 
-The CPIO archive is the preferred method of packaging the //​initramfs//​. We could also do it manually using the **cpio** tool (see example below) but since the option is there... why not? 
- 
-<code bash> 
-$ cd /​path/​to/​rootfs 
-$ find . | cpio -o > /​path/​to/​ramdisk.cpio 
-</​code>​ 
-</​note>​ 
- 
-Feel free to add / remove anything else you want. Anything goes as long as you end up with a functioning system. 
-After completing Step 3, maybe return and see if there'​s anything left to trim down to speed up the build process 
- 
-<​solution -hidden> 
-Changes that I made to BR defconfig: 
-<code diff> 
-diff --git a/​configs/​imx8mqevk_defconfig b/​configs/​imx8mqevk_defconfig 
-index 943a479932..1d658f37e8 100644 
---- a/​configs/​imx8mqevk_defconfig 
-+++ b/​configs/​imx8mqevk_defconfig 
-@@ -1,39 +1,28 @@ 
- ​BR2_aarch64=y 
- ​BR2_ARM_FPU_VFPV3=y 
--BR2_PACKAGE_HOST_LINUX_HEADERS_CUSTOM_5_8=y 
-+BR2_TOOLCHAIN_EXTERNAL=y 
-+BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y 
-+BR2_TOOLCHAIN_EXTERNAL_PATH="/​home/​mants/​workspace/​arm-summer-school/​test/​toolchains/​aarch64"​ 
-+BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="​aarch64-none-linux-gnu"​ 
-+BR2_TOOLCHAIN_EXTERNAL_GCC_10=y 
-+BR2_TOOLCHAIN_EXTERNAL_HEADERS_4_20=y 
-+BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC=y 
-+# BR2_TOOLCHAIN_EXTERNAL_INET_RPC is not set 
-+BR2_TOOLCHAIN_EXTERNAL_CXX=y 
-+BR2_INIT_SYSTEMD=y 
- ​BR2_TARGET_GENERIC_GETTY_PORT="​ttymxc0"​ 
--BR2_ROOTFS_POST_IMAGE_SCRIPT="​board/​freescale/​common/​imx/​imx8-bootloader-prepare.sh board/​freescale/​common/​imx/​post-image.sh"​ 
--BR2_ROOTFS_POST_SCRIPT_ARGS="​${UBOOT_DIR}/​arch/​arm/​dts/​imx8mq-evk.dtb"​ 
--BR2_LINUX_KERNEL=y 
--BR2_LINUX_KERNEL_CUSTOM_VERSION=y 
--BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="​5.8.7"​ 
--BR2_LINUX_KERNEL_USE_ARCH_DEFAULT_CONFIG=y 
--BR2_LINUX_KERNEL_DTS_SUPPORT=y 
--BR2_LINUX_KERNEL_INTREE_DTS_NAME="​freescale/​imx8mq-evk"​ 
--BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y 
-+BR2_SYSTEM_DEFAULT_PATH="/​bin:/​sbin:/​usr/​bin:/​usr/​sbin"​ 
-+# BR2_PACKAGE_BUSYBOX is not set 
- ​BR2_PACKAGE_FREESCALE_IMX=y 
- ​BR2_PACKAGE_FREESCALE_IMX_PLATFORM_IMX8M=y 
- ​BR2_PACKAGE_FIRMWARE_IMX=y 
--BR2_TARGET_ROOTFS_EXT2=y 
--BR2_TARGET_ROOTFS_EXT2_4=y 
--BR2_TARGET_ROOTFS_EXT2_SIZE="​120M"​ 
--BR2_TARGET_ARM_TRUSTED_FIRMWARE=y 
--BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_TARBALL=y 
--BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_TARBALL_LOCATION="​$(call github,​nxp-imx,​imx-atf,​rel_imx_5.4.24_2.1.0)/​imx-atf-rel_imx_5.4.24_2.1.0.tar.gz"​ 
--BR2_TARGET_ARM_TRUSTED_FIRMWARE_PLATFORM="​imx8mq"​ 
--BR2_TARGET_ARM_TRUSTED_FIRMWARE_BL31=y 
--BR2_TARGET_UBOOT=y 
--BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y 
--BR2_TARGET_UBOOT_CUSTOM_TARBALL=y 
--BR2_TARGET_UBOOT_CUSTOM_TARBALL_LOCATION="​$(call github,​nxp-imx,​uboot-imx,​rel_imx_5.4.24_2.1.0)/​uboot-imx-rel_imx_5.4.24_2.1.0.tar.gz"​ 
--BR2_TARGET_UBOOT_BOARD_DEFCONFIG="​imx8mq_evk"​ 
--BR2_TARGET_UBOOT_NEEDS_DTC=y 
--BR2_TARGET_UBOOT_FORMAT_CUSTOM=y 
--BR2_TARGET_UBOOT_FORMAT_CUSTOM_NAME="​u-boot-nodtb.bin"​ 
--BR2_TARGET_UBOOT_SPL=y 
-+BR2_TARGET_ROOTFS_CPIO=y 
-+# BR2_TARGET_ROOTFS_TAR is not set 
- ​BR2_PACKAGE_HOST_DOSFSTOOLS=y 
-+BR2_PACKAGE_HOST_E2FSPROGS=y 
- ​BR2_PACKAGE_HOST_GENIMAGE=y 
- ​BR2_PACKAGE_HOST_IMX_MKIMAGE=y 
-+BR2_PACKAGE_HOST_KMOD=y 
- ​BR2_PACKAGE_HOST_MTOOLS=y 
- ​BR2_PACKAGE_HOST_UBOOT_TOOLS=y 
- ​BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y 
-</​code>​ 
-</​solution>​ 
- 
-== Step 3: Build it! == 
- 
-Not much to it, really. Once everything'​s done, check out the ''​output/''​ directory. What does it contain? Where is your CPIO archive? 
- 
-<note important>​ 
-Chances are that you're going to screw something up while playing around with the config file. Check the error message and if it's not immediately obvious try to find the makefile / script where things go awry. If a ''​grep -rn ${ERROR_MESSAGE}''​ doesn'​t help, try to run **make** with the ''​V=1''​ argument for verbose output, but without ''​-j''​. 
-</​note>​ 
ass/laboratoare/02/tasks/01.1689436408.txt.gz · Last modified: 2023/07/15 18:53 by radu.mantu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0