U-Boot hangs while loading kernel? - linux-kernel

I am working on Freescale board imx50evk. I have built the uboot.bin and uImage using LTIB (linux target image builder). At the U-Boot prompt I enter the bootm addr command, and then it hangs after showing the message "Loading Kernel..."
> MX50_RDP U-Boot > boot
MMC read: dev # 0, block # 2048, count 6290 partition # 0 ...
6290 blocks read: OK
## Booting kernel from Legacy Image at 70800000 ...
Image Name: Linux-2.6.35.8
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1323688 Bytes = 1.3 MB
Load Address: a0008000
Entry Point: a0008000
Verifying Checksum ... OK
Loading Kernel Image ...

You need to verify that your board really has RAM at 0xa0008000, which is the kernel "load address". U-Boot is probably trying to copy the image to that region of memory when it appears to hang.
[By your comment, I'll assume that you have verified that main memory does not exist at physical address 0xAXXXXXXX.]
The uImage file that you are using was made from the zImage file using the mkimage utility.
You probably have to manually edit the line that looks like
zreladdr-y := 0xa0008000
in arch/arm/mach-XXX/Makefile.boot for your board. The convention is that this address should be the base of physical RAM plus an offset of 0x8000 (32K). Then adjust the other values in the file. Delete the zImage file and perform another make for the kernel.

While building 3.20 development kernels for rockchip's rk3288 I found using LZO image compression made the device hang at 'Starting the kernel.' I assume it's because of a version miss-match between the build hosts LZO and the deployed decompression code, so it could probably happen with any of the compression algorithms. In my case switch to gzip fixed it.
This is only my assumption for why changing the compression algorithm gave a bootable kernel. Please correct me if I'm wrong.

Related

why is load address of kernel, ramdisk important in booting?

I am dealing with android boot.img which is a combination of compressed kernel, ramdisk, and dtb. I see from the serial console log from uboot about the booting process and here's the part that triggers my curiosity
CPU: Freescale i.MX6Q rev1.2 at 792 MHz
CPU: Temperature 27 C
Reset cause: POR
Board: MX6-SabreSD
I2C: ready
DRAM: 1 GiB
PMIC: PFUZE100 ID=0x10
MMC: FSL_SDHC: 0, FSL_SDHC: 1, FSL_SDHC: 2
No panel detected: default to Hannstar-XGA
Display: Hannstar-XGA (1024x768)
In: serial
Out: serial
Err: serial
check_and_clean: reg 0, flag_set 0
Fastboot: Normal
flash target is MMC:1
Net: FEC [PRIME]
Normal Boot
Hit any key to stop autoboot: 3 2 1 0
boota mmc1
kernel # 14008000 (7272352)
ramdisk # 15000000 (869937)
fdt # 14f00000 (44072)
## Booting Android Image at 0x12000000 ...
Kernel load addr 0x14008000 size 7102 KiB
Kernel command line: console=ttymxc0,115200 init=/init video=mxcfb0:dev=hdmi,1920x1080M#60,bpp=32 video=mxcfb1:off video=mxcfb:off video=mxcfb3:off vmalloc=256M androidboot.console=ttymxc0 consolebalank=0 androidboot.hardware=freescale cma=384M
## Flattened Device Tree blob at 14f00000
Booting using the fdt blob at 0x14f00000
Loading Kernel Image ... OK
Using Device Tree in place at 14f00000, end 14f0dc27
switch to ldo_bypass mode!
Starting kernel ...
The kernel's address is 14008000, ramdisk 15000000, fdt 14f00000.
I have found out that these values are saved in the boot.img header and when I manually mess with this values, the image will not boot even though the actual contents are not modified.
Why is this address so critical? Why does it have to be these values? why not other values?
One of my own guess is:
these load address values are hardcoded inside the kernel so if I change it in the boot.img header it will cause side-effects. To elaborate my own theory, loading the kernel to the 'modified' load addr won't be a problem. But when actually executing the lines, it will cause severe problems because these codes are fixed to work with the proper 'load addr'.
Is my theory wrong? If so, I'd be grateful if you could correct me.
After the U-boot finished, it needs to handover the further execution to kernel so that kernel takes care for all further processes. Plus Kernel have some set of routines which are essential to initialize the board.
These set of routines have a entry point start_kernel(). Before this some other routines are also called to execute start_kernel. That can be identified by this linker script and this init.S.
To maintain execution in this procedure kernel need to be started from a particular address, moreover its data segments and other memories are also attached with that so to load and run all these in a proper manner, exact memory location need to be provided.
With this kernel needs the device tree blob for probing the devices attached to it and the rootfs to bring up the user space, here to load the device tree and rootfs exact offsets are needed so that any data should not be missed or corrupted. Every single byte is important for all these execution.
So to safely bootup all these values are being stored in bootloader's configuration.

Size constraints of initramfs on ARM?

I'm creating a bootable Linux system on a PicoZed board (ARM CortexA9 core), and I've run into a "limitation", which I don't think really is a limitation (I get the feeling it's another problem masquerading as a limitation).
I boot by starting the system in JTAG boot mode; after powering on the board I use the xmd debugger to place u-boot into the system's RAM and then I run it.
Next I place the kernel (uImage), the gzip'd initramfs image and the device tree into memory. Finally I tell u-boot to boot the system using bootm, and using three arguments to point out the memory locations of all the images.
All of this works, and I manage to boot up Linux + userland. However, I need to grow the initramfs, and this is where I run into problems.
The working image is 16MiB exactly. I tried to make it 24MiB (completely regenerated from scratch each time I try to boot), but just after the kernel has loaded and it tries to find init the kernel reports file system faults and fails. There shouldn't be any overlaps, but just in case I tried moving things around a little, but the same problem occurred.
After searching for some tips, I saw someone on a forum say that the image needs to be placed at a 16MiB alignment (which I don't think is true, but I tried it none the less, but it didn't get a working system). Another post claimed that the images must be aligned with their sizes (which I again don't think is true, but I tried that as well, but with no change). Yet another post claimed that this happens if the initramfs image crosses the __init end boundary, and that placing the initramfs image firmly inside will allow the memory to be reclaimed after the image has been uncompressed by the kernel, and placing it beyond the __init section will work but then that memory is forever lost after boot. I know way too little about Linux in order to know if any of this is in any way true/accurate, and I have no idea where "__init"'s - if such a thing exists - end-boundary is, but if the issue is that I was crossing it I tried moving the initramfs image way beyond anywhere were I was previously using it, but that didn't change anything.
I also tried the original location (which works with a 16MiB image) and create a 16MiB + 1K sized image, but this didn't work either. (Checking that it didn't overlay any of the over images, obviously).
This originally led me to think there's a 16MiB initramfs size limit lurking somewhere. But on searching for it, it got me thinking that doesn't make sense -- as far as I can gather the bootm command in u-boot shoud set up the tag list for the system (which includes the location and size of the initramfs), and I haven't come across any note about a 16MiB limit in relation to the tagged lists for the initramfs so far.
I have found a page which claims that the initramfs size is in practical terms limited to roughly half the size of physical ram in the system, and the PicoZed board has 1G RAM, so we're in orders of magnitude away from what "should" be a limitation.
To clarify: The 16MiB image is the size of the raw image; compressed it's just under 6MiB. However, if I populate it so it's not compressed as tightly it doesn't make any difference -- the problem doesn't appear to be related to the size of the compressed image, only the uncompressed image.
Main question:
Where is this apparent 16MiB initramfs size limit coming from?
Side-question:
Is there such a thing as an "kernel __init section" which is reclaimed by the kernel after it has uncompressed/loaded images? If so, how do I see/configure the location/size of it?
Size constraints of initramfs on ARM?
I have not encountered a 16 MiB size constraint as you allege.
At one time I thought there was a size limit too, but that turned out to be a memory footprint issue during boot. Once that was sorted out I've been using large initramfs of 30MiB (e.g. with glibc, gtstreamer and qt5 libraries).
Where is this apparent 16MiB initramfs size limit coming from?
There isn't one. A ramfs is only constrained by available RAM.
There is a definition for the "Default RAM disk size", but this would not affect the size of an initramfs.
Your method of booting with the U-Boot bootm command is suspect, i.e. you're passing the memory address of the initramfs as the second argument.
The U-Boot documentation clearly describes the second argument as "the address of an initrd image" (emphasis added).
There is no mention of initramfs as an argument.
Linux kernel documentation states that the initramfs archive can be "linked into the linux kernel image". There's a kernel menuconfig entry for specifying the path to the initramfs cpio file. The make script will append this cpio file to the kernel image so that there is a single image file for booting.
Or (like an initrd) "a separate file" can be passed to the kernel at boot to populate the initramfs.
U-Boot passes the location (and length) of this archive either as an ATAG entry or as a reserved memory region in the Device Tree blob.
The kernel expects either a cpio archive for the initramfs or a tar archive for an initrd.
You neglect to mention (besides its compression) what kind of archive this "initramfs" or "separate file" actually is .
So it's not clear if you're booting the kernel with an initrd (tar archive) or an initramfs (cpio archive).
Your repeated reference to the initramfs as an "image" file rather than a cpio archive suggests that you really are using an initrd.
An initrd would definitely have a size constraint.
Is there such a thing as an "kernel __init section" which is reclaimed by the kernel after it has uncompressed/loaded images?
Yes, there is an __init section of memory, which is released after kernel initialization is complete.
If so, how do I see/configure the location/size of it?
Usually routines and data that have no use after initialization can be declared with the __init macro. See this.
The location and size of this memory section would be under the control of the linker script, rather than explicit user control. The kernel System.map file should have the info for review.
I think you need to pass ramdisk_size in uboot bootargs command
ramdisk_size needs to be set if the ram-disk uncompress file
size is bigger than default setting. It should be more than
ramdisk uncompress file size.

what's the difference between 'load mmc' and 'load addr'?

Here's my u-boot
## Booting kernel from Legacy Image at 42000000 ...
Image Name: Linux-4.1.8
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3458160 Bytes = 3.3 MiB
Load Address: 70008000
Entry Point: 70008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
Starting kernel ...
And it stuck.
what's the difference between the 42000000 and the 70008000? Should the two be the same?
Booting kernel from Legacy Image at 42000000 ...
This first address is the one where u-boot will look for the (probably compressed) linux kernel image.
Load Address: 70008000
is the address where u-boot will copy the decompressed linux kernel image
Entry Point: 70008000 - linux kernel entry point address
Once the linux image has been decompressed and copied to the load address location, the entry point is the address where to start executing the kernel image, that in this case is exactly the start of the memory area where the kernel has been copied.
You can find further detail # below link:
http://lists.denx.de/pipermail/u-boot/2007-March/020043.html
https://balau82.wordpress.com/2010/04/12/booting-linux-with-u-boot-on-qemu-arm/

Linux Kernel Booting Approach Pre built rootfs

I am learning the linux kernel booting process and trying to install linux on my beagleboard xM. I came across two approach both using the SD card.
1. Have the MLO, initrd, uboot.bin and uImage in one partition.
2. Have the MLO, uboot.bin and uImage in one partition and a pre-built rootfs (Angstrom) in 2nd partition.
In the first approach how is the initrd transformed into a complete file system on the 2nd partition. And what happens internally when uboot extracts the kernel from uImage and paste it on the 2nd partition. which directories would get modified of the init rootfs. How the init process of the kernel is called.
In general, the booting sequence in the Beagleboard-XM is something like this :
Firmware -> MLO -> uboot.bin -> uImage -> initrd(optional) -> rootfs
The initrd itself is a simple RAM based file system. It is generally used to mount the actual file system. Some of the modules which are required to mount the rootfs are bundled up into the initrd. Once the rootfs is mounted, the initramfs is cleaned up. If the features that are required to mount the rootfs is built into the kernel (uImage) itself, then there is no need of initrd. As I said earlier, initrd is a simple RAM based file system. That means if you use this as your filesystem, anything you write onto it will not be preserved. A few embedded applications actually use this as their rootfs.
Now answering to your question,
How is the initrd transformed into a complete file system on the 2nd partition?
Initially u-boot loads the kernel(uImage), initrd onto RAM and pass the appropriate the command line arguments to the kernel. Once the u-boot transfers the control over to the kernel, it first initializes the drivers and other modules and finally looks for initrd. The initrd is generally put as a cpio image. The kernel then uncompresses it and looks for 'init'. The init processes few things and then mounts the rootfs. There is no such thing as 2nd partition when it comes to initrd. It resides on the RAM.
What happens internally when uboot extracts the kernel from uImage and paste it on the 2nd partition?
Again, there is no such things as 2nd partition when it comes to uImage. uImage is a format which is understood by u-boot. The u-boot first loads the uImage onto the RAM and before actually passing the control over to the kernel, it extracts the contents from uImage, moves the binary to a predefined location in the RAM and then passes the control over to the kernel. Similar to initrd, the kernel also resides on the RAM itself.
Which directories would get modified of the init rootfs?
No directories gets modifies. But yes, a few of them are mounted, like procfs, sysfs, etc.
How the init process of the kernel is called?
Please refer to the kernel_init() function under init/main.c to see how the kernel executes init (refer http://lxr.free-electrons.com/source/init/main.c#L871).
I am attaching a simple code snippet from it :
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/init.txt for guidance.");
Therefore, the kernel searches in these default paths for the init binary. If it is not found, the kernel panics!
Hope this helps.

The using of address ZTEXTADDR in Linux booting for ARM

What is the role of ZTEXTADDR in Linux kernel ?
From lxr.linux.no, it's an address in RAM that holds address of zImage as sequence below?
A.
uImage (DataFlash/NAND) ---load_to_RAM--->
uImage (# boot_addr) ---decompress_uImage-->
zImage (# ZTEXTADDR) --- decompress_zImage--->
uncompressed image (# ZRELADDR).
or just:
B.
uImage (DataFlash/NAND) ---load_to_RAM--->
uImage (# boot_addr) ---decompress_uImage-->
uncompressed image (# ZRELADDR)
no using ZTEXTADDR in new kernel version for booting process ?
The Linux ARM decompression boot loader is capable of relocating itself when running from RAM. The relocation portion is PC-relative and so it can be loaded at any address. However, if your main image starts from FLASH/ROM, the code can not be relocated; while moving an image in RAM is a simple memmove(), it is much more involved for NOR flash and can be impossible for ROM.
In this case, a compressed boot linker script is used with the ZTEXTADDR as the location of the decompression code. In your diagram, you have a u-boot, which will load the uImage. There is no reason to execute this directly from Flash/ROM. u-boot can copy the image to RAM and there is no need for the ZTEXTADDR value and it should be left as zero.
If your image boots directly from Flash/ROM, without a boot loader then ZTEXTADDR is useful,
zImage (in flash) --> decompress vmlinux.bin to RAM --> run kernel
The zImage may need to be annotated with some chip setup for this to work and would need ATAGS or device trees linked. For this reason, there are many machine variants in boot/compressed; This is not maintainable and these type of files are discouraged. Typically another bootloader loads the image to RAM and the zImage can move itself to whatever destination it needs; I think that is your situation and you should set ZTEXTADDR to zero and forget about it.

Resources