“Unsupported machine ID” after upgrading Linux kernel or U-boot

This post was written by eli on February 20, 2014
Posted Under: ARM,Linux kernel,Zynq

Unlike how I usually treat software tools I work with, my attitude towards U-boot is “if it works, never mind how and why”. Trying to understand the gory details of U-boot has never been very rewarding. Things work or break more or less randomly, depending on which git revision is checked out. Someone sent a patch fixing this and breaking that, and then someone else sent another patch.

So this is my story: After upgrading the Linux kernel from 3.3 to 3.12 (both having a strong Xilinx flavor, as the target is a Zynq board), but kept an old version of U-boot, I ran through the drill that usually makes the kernel boot:

zynq-uboot> fatload mmc 0 0x8000 zImage
reading zImage

2797680 bytes read
zynq-uboot> fatload mmc 0 0x1000000 devicetree.dtb
reading devicetree.dtb

5827 bytes read
zynq-uboot> go 0x8000
## Starting application at 0x00008000 ...

Error: unrecognized/unsupported machine ID (r1 = 0x1fb5662c).

Available machine support:

ID (hex)        NAME
ffffffff        Generic DT based system
ffffffff        Xilinx Zynq Platform

Please check your kernel config and/or bootloader.

So the kernel didn’t boot. Looking at the way I attempted to kick it off, one may wonder how it worked at all with kernel v3.3. But one can’t argue with the fact that it used to boot.

The first thing to understand about this error message, is that it’s fatally misleading. The real problem is that the device tree blob isn’t found by the kernel, so it reverts to looking for a machine ID in r1. And r1 just has some value. The error message comes from a piece of boot code that is never reached, if the device tree is found and used.

Now, let’s try to understand the logic behind the sequence of commands: The first command loaded the zImage into a known place in memory, 0x8000. One could ask why I didn’t use uImage. Well, why should I? zImage works, and that’s the classic way to boot a kernel.

The device tree blob is then loaded to address 0x10000000.

And then comes the fun part: U-boot just jumps to 0x8000, the beginning of the image. I think I recall that one can put zImage anywhere in memory, and it will take it from there.

But how does the kernel know that the device tree is at 0x10000000? Beats me. I suppose it’s hardcoded somewhere. But hey, it worked! At least on older kernels. And on U-boot 2012.10 and older (but not 2013.10).

For the newer kernel (say, 3.12), a completely different spell should be cast. Something like this (using U-Boot 2012.10 or 2013.10):

zynq-uboot> fatload mmc 0 0x3000000 uImage
reading uImage                                                                  

3054976 bytes read
zynq-uboot> fatload mmc 0 0x2A00000 devicetree.dtb
reading devicetree.dtb                                                          

7863 bytes read
zynq-uboot> bootm 0x3000000 - 0x2A00000
## Booting kernel from Legacy Image at 03000000 ...
   Image Name:   Linux-3.12.0-1.3-xilinx
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    3054912 Bytes = 2.9 MiB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 02a00000
   Booting using the fdt blob at 0x02a00000
   Loading Kernel Image ... OK
OK
   Loading Device Tree to 1fb4f000, end 1fb53eb6 ... OK                         

Starting kernel ...                                                             

Uncompressing Linux... done, booting the kernel.
Booting Linux on physical CPU 0x0
[ ... kernel boots, bliss and happiness ... ]

OK, so I twisted it all around. All of the sudden, I use an uImage, rather than zImage. Why? Because bootm works with uImage, and bootz wasn’t supported by that specific U-boot version (or configuration, I’m not really sure).

The addresses I loaded into are different too, and I’m not sure it matters. What surely matters, is that bootm was explicitly given the address of the device tree blob, and therefore passed that through a register to the kernel. So in this case, it’s pretty obvious how the kernel finds what’s where.

Ah, but there’s a twist. The latter, bootm-based method didn’t work on the 3.3 kernel. In fact, I got a very similar error message when I tried that.

As I said in the beginning, I never cared dive deep into U-boot. So all I’m saying is — if you encounter an error message like the one above, just try the other magic spell, and hope for good.

And if someone known more about what happened in the connection between U-boot and Linux somewhere in 2012, or has a link to some mailing list discussion where this was decided upon, please comment below. :)

Reader Comments

Look at this:
http://www.wiki.xilinx.com/Zynq+Linux

“Device Tree In Memory
The kernel has 2 ways it can find a device tree in memory. The 1st and industry standard method is that it expects the address of the device tree to be in register R2 when the boots. Starting in 14.3 this is the default kernel configuration, but it was not previously.

The 2nd method, and the default in the Xilinx kernel configuration, is hard coded such that it expects the device tree at address 0x1000000 (16 MB). This is referred to as Device Tree At Fixed Address in the kernel configuration. The purpose of the fixed address for a device tree is to allow the go command in u-boot (which does not set up R2 to point to the device tree) to continue to be used.

This method can be enabled in the kernel configuration and must be disabled if a device tree is to loaded at other addresses while using the bootm command in u-boot.
Note that the Device Tree At Fixed Address kernel configuration option is only available in the menu when device tree has been enabled in the kernel configuration.”

#1 
Written By Andras Gal on May 19th, 2015 @ 10:44

Add a Comment

required, use real name
required, will not be published
optional, your blog address