Differences

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

Link to this comparison view

ass:laboratoare:01:tasks:02 [2023/07/17 22:55]
florin.stancu
ass:laboratoare:01:tasks:02 [2024/08/04 22:07] (current)
florin.stancu [02. Creating the Firmware Image Package]
Line 66: Line 66:
 === 02-C. Build U-Boot (both BL2 and BL33) === === 02-C. Build U-Boot (both BL2 and BL33) ===
  
-For the last two components of our Firmware Package we'll be using [[https://​github.com/​TechNexion/​u-boot-tn-imx|U-Boot]]. Each of them has a very specific purpose.+For the last two components of our Firmware Package we'll be using [[https://​github.com/​TechNexion/​u-boot-tn-imx|this U-Boot ​fork]] (clone it!). 
 +Each of them has a very specific purpose.
  
 At first, **BL1** will //start// downloading the FIP (Firmware Image Package, which we'll generate later) using the Serial Download Protocol, running on top of a USB connection. At first, **BL1** will //start// downloading the FIP (Firmware Image Package, which we'll generate later) using the Serial Download Protocol, running on top of a USB connection.
Line 72: Line 73:
  
 <note warning> <note warning>
-The more astute will notice that once again we're not using the [[https://​github.com/​u-boot/​u-boot|official U-Boot]] project, but instead ​the TechNexion (i.e. the dev board manuafcturer) fork. As we've mentioned before, **BL2** will have to take over the serial download over USB from **BL1**. However, it can not reuse the drivers that **BL1** was using. Mainly because it overrides **BL1** in SRAM with **BL31**. ​So; what's the problem?+The more astute will notice that, **once again**, we're not using the [[https://​github.com/​u-boot/​u-boot|official U-Boot]] project, but instead TechNexion'​s ​(i.e. the board's manufacturer) fork. 
 +As we've mentioned before, **BL2** will have to take over the serial download over USB from **BL1**. 
 +However, it can not reuse the drivers that **BL1** was using. 
 +Mainly because it overrides **BL1** in SRAM with **BL31**.
  
-Since the release of our board, U-Boot has seen some improvements with respect to certain drivers that are necessary to us. These improvements increased the size of **BL2** to the point that it no longer fits in the board'​s SRAM. Even with Link Time Optimizations which usually help in this regard, and with some attempts at removing useless drivers, it's still <​del>​a pain in the ass</​del>​ challenging to make everything fit. The TechNexion fork has the advantage of being slightly outdated and having been tested at some point by one of their developers.+So... what's the problem? 
 +Since the release of our board, U-Boot has seen some improvements with respect to certain drivers that are necessary to us. 
 +These improvements increased the size of **BL2** to the point that it no longer fits in the board'​s SRAM (''​128KB :( ''​). 
 + 
 +Even with Link Time Optimizations which usually help in this regard, and with some attempts at removing useless drivers ​(we've wasted 1 day trying to do it), it's still <​del>​a pain in the ass</​del>​ challenging to make everything fit. 
 +The TechNexion fork has the advantage of being slightly outdated and having been tested at some point by one of their developers.
 </​note>​ </​note>​
  
 When **BL31** runs its course, **BL33** will be called upon. During this phase we'll finally have an interactive shell and multiple drivers to help interact with the board. With this, we can investigate the board'​s hardware, read and potentially override the partitions in the persistent storage and most importantly,​ boot Linux from any number of sources. When **BL31** runs its course, **BL33** will be called upon. During this phase we'll finally have an interactive shell and multiple drivers to help interact with the board. With this, we can investigate the board'​s hardware, read and potentially override the partitions in the persistent storage and most importantly,​ boot Linux from any number of sources.
  
-== Step 4: Generate ​a default ​configuration ==+== Step 3: Generate ​the configuration ==
  
 +Alright, let's get to it!
 U-Boot is based on the same build system as the Linux kernel, namely [[https://​www.kernel.org/​doc/​html/​latest/​kbuild/​index.html|Kbuild]]. To get an idea of what functionality it provides, try to run: U-Boot is based on the same build system as the Linux kernel, namely [[https://​www.kernel.org/​doc/​html/​latest/​kbuild/​index.html|Kbuild]]. To get an idea of what functionality it provides, try to run:
  
Line 89: Line 99:
 If you check the ''​configs/''​ directory, you will find a number of board-specific configuration files. These serve as templates, containing the minimal necessary configuration. By running ''​make some_defconfig''​ the Kbuild system will determine what other unspecified options need to be enabled in order for these features to be functional. The result will be saved in a file called ''​.config''​. If you check the ''​configs/''​ directory, you will find a number of board-specific configuration files. These serve as templates, containing the minimal necessary configuration. By running ''​make some_defconfig''​ the Kbuild system will determine what other unspecified options need to be enabled in order for these features to be functional. The result will be saved in a file called ''​.config''​.
  
-Generate a ''​.config''​ for your board. Also, don't forget ​the ''​CROSS_COMPILE'' ​variable from **BL31**. It's very common across such projects and Kbuild will actually complain if it believes that you're trying to use a x86 compiler.+Generate a ''​.config''​ for your board by running ​the ''​make <board's name>​_defconfig''​.
  
-== Step 2: Modify ​the configuration ==+Also, don't forget ​the ''​CROSS_COMPILE''​ variable from **BL31** (you'​ve exported it, right? if not, pass it as ''​KEY=VALUE'''​ argument to make). 
 +It's very common across such projects and Kbuild will actually complain if it sees that you're trying to use a x86 compiler.
  
-The default configuration that you chose (correctly, hopefully) contains a few erroneous values for the USB driver. Normally these would take some time to dig up from the board'​s / processor'​s documentation;​ we took them from the debug prints of the firmware that was pre-configured on the eMMC :p+== Step 4: Modify the configuration == 
 + 
 +The default configuration that you chose (correctly, hopefully) contains a few erroneous values for the USB driver. 
 +Normally these would take some time to dig up from the board'​s / processor'​s documentation ​/ source code; we took them from the debug prints of the firmware that was pre-configured on the eMMC :P
  
 Open a ncurses-based interface for editing the ''​.config''​ file: Open a ncurses-based interface for editing the ''​.config''​ file:
Line 109: Line 123:
   * **USB_GADGET_PRODUCT_NUM:​** 0x012b   * **USB_GADGET_PRODUCT_NUM:​** 0x012b
  
-== Step 3: Build it! ==+== Step 5: Build it! == 
 + 
 +Run the make command (again, don't forget the cross compiler argument, if you haven'​t exported it already)!
  
 The three files you should obtain are: The three files you should obtain are:
 +
   * **spl/​u-boot-spl.bin:​** aka. **BL2**.   * **spl/​u-boot-spl.bin:​** aka. **BL2**.
   * **u-boot-nodtb.bin:​** aka. **BL33**.   * **u-boot-nodtb.bin:​** aka. **BL33**.
-  * **arch/​arm/​dts/​imx8mq-pico-pi.dtb:​** a Device Tree Blob (DTB); see details below.+  * **arch/​arm/​dts/​imx8mq-pico-pi.dtb:​** a Device Tree Blob (DTB) which we'll also require; see details below.
  
 <​note>​ <​note>​
-You may be wondering what is up with the //.dtb// file. This file is a Device Tree Blob (DTB) and represents the hardware available on the board. On most ARM platforms this is required since there is no Device Enumeration method, unlike on most x86 systems (e.g.: [[https://​kernel.org/​doc/​html/​v5.18/​firmware-guide/​acpi/​enumeration.html|ACPI]]). Without it, Linux would have no idea how to identify or interact with its devices or what drivers to put in charge of managing them. We are going to discuss this topic more in-depth next session. For now, if you are curious, you can decompile the DTB into a human-readable Device Tree Source (DTS):+You may be wondering what is up with the //.dtb// file. This file is a Device Tree Blob (DTB) and represents the hardware available on the board. 
 + 
 +On most ARM platforms this is required since there is no Device Enumeration method, unlike on most x86 systems (e.g.: [[https://​kernel.org/​doc/​html/​v5.18/​firmware-guide/​acpi/​enumeration.html|ACPI]]). 
 + 
 +Without it, Linux would have no idea how to identify or interact with its devices or what drivers to put in charge of managing them. We are going to discuss this topic more in-depth next session. For now, if you are curious, you can decompile the DTB into a human-readable Device Tree Source (DTS):
  
 <code bash> <code bash>
Line 123: Line 144:
 $ dtc -I dtb -O dts imx8mq-pico-pi.dtb | less $ dtc -I dtb -O dts imx8mq-pico-pi.dtb | less
 </​code>​ </​code>​
 +Of course, you could find the original code by [[https://​github.com/​TechNexion/​u-boot-tn-imx/​blob/​tn-imx_v2022.04_5.15.71_2.2.0-stable/​arch/​arm/​dts/​imx8mq-pico-pi.dts|exploring u-boot'​s source code]]!
 </​note>​ </​note>​
  
 === Task D - Generate the firmware package === === Task D - Generate the firmware package ===
  
-Now that we have all necessary binaries, all that is left is to combine them in a manner that can be understood by **BL1**.+Now that we have all necessary binaries ​either downloaded or compiled ourselves, all that is left is to combine them in a manner that can be understood by the processor'​s first boot stage (**BL1**).
  
 Since 2022, U-Boot'​s tool of choice for this task is [[https://​u-boot.readthedocs.io/​en/​latest/​develop/​package/​binman.html|binman]]. This tool uses a platform-specific config file that specifies what components should be included and where they should be placed in memory. For our platform (i.e.: i.MX8M Quad) this file would be ''​arch/​arm/​dts/​imx8mq-u-boot.dtsi''​. Since 2022, U-Boot'​s tool of choice for this task is [[https://​u-boot.readthedocs.io/​en/​latest/​develop/​package/​binman.html|binman]]. This tool uses a platform-specific config file that specifies what components should be included and where they should be placed in memory. For our platform (i.e.: i.MX8M Quad) this file would be ''​arch/​arm/​dts/​imx8mq-u-boot.dtsi''​.
  
-However, since the U-Boot version that we are using is older and the board manufacturer did not add proper support for binman, we are going to use the older method, based on [[https://​linux.die.net/​man/​1/​mkimage|mkimage]] (part of the U-Boot repo or as a package on most distros). In order to spare ourselves some pain, we are going to use NXP's [[https://​github.com/​nxp-imx/​imx-mkimage/​tree/​lf-5.15.32_2.0.0|imx-mkimage]] implementation which knows the proper offsets where the images should be loaded.+**However**, since the U-Boot version that we are using is older and [[https://​github.com/​TechNexion/​u-boot-tn-imx/​commit/​ca11907c0e7b7efd22f037793295fb0427e05ecb|the board manufacturer did not add proper support for binman]]**we are going to use the older method**, based on [[https://​linux.die.net/​man/​1/​mkimage|mkimage]] (part of the U-Boot repo or as a package on most distros). In order to spare ourselves some pain, we are going to use NXP's [[https://​github.com/​nxp-imx/​imx-mkimage/​tree/​lf-5.15.32_2.0.0|imx-mkimage]] implementation which knows the proper offsets where the images should be loaded.
  
-In their source tree you will find a number of subdirectories corresponding to different versions of the i.MX platform. Select the one which corresponds to our board. ​There you will have to copy all the bootloaders you compiled so far, as well as the downloaded firmware. In addition to these, you will have to copy the **mkimage** tool (available in the U-Boot repowith the name **mkimage_uboot**.+In their source tree you will find a number of subdirectories corresponding to different versions of the i.MX platform. Select the one which corresponds to our board (remember, the base model is called //iMX8M//). 
 +When you get there, ​you will have to copy all the bootloaders you compiled so far, as well as the downloaded firmware ​(trust us here: **make a script to do this automatically**! you'll need to do it tens -- probably hundreds -- of times!).
  
-Once you have all these, run make with the ''​flash_evk''​ target, while specifying the platform in the ''​SOC''​ argument and the name of the DTB copied over from U-Boot in the ''​dtbs''​ argument. The output ​FIP should be called **flash.bin**.+In addition to these, you will have to copy the base **mkimage** tool (generated in the U-Boot directory, see if you can ''​find''​ it '';​)''​ ); rename it as **mkimage_uboot**. 
 + 
 +Once you have all these, run make with the ''​flash_evk''​ target, while specifying the platform in the ''​SOC='' ​make argumentand the name of the DTB copied over from U-Boot in the ''​dtbs=''​ argument. The output ​firmware image should be called **flash.bin**.
  
 <​note>​ <​note>​
Line 146: Line 171:
 The last two sub-tasks demonstrate that the DTB format is very versatile. On one hand, it is used to describe the available hardware to the Linux kernel. On the other hand, image packaging tools rely on them to determine the layout of different binaries in memory. The last two sub-tasks demonstrate that the DTB format is very versatile. On one hand, it is used to describe the available hardware to the Linux kernel. On the other hand, image packaging tools rely on them to determine the layout of different binaries in memory.
 </​note>​ </​note>​
 +
ass/laboratoare/01/tasks/02.1689623738.txt.gz · Last modified: 2023/07/17 22:55 by florin.stancu
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