I'm trying to understand the details of linux booting on arm architecture. I did lot of search on the internet and understood so far some details although I feel each time I read an article it brings lot of other new terms and this makes things more complex. I do have 2 boards running linux, an olimex 9261 and a beaglebone black. My expertise in embedded systems especially arm is pretty good, but didn't play too much with linux though (except some user space programs and char drivers in kernel).
Here are my questions:
One one board I have the following uboot output (linux 2.6.30):
bootargs=mem=64M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2
bootcmd= cp.b 0xC0042000 0x22000000 0x00199954; bootm 0x22000000
The board has 64MB RAM (mapped at 0x20000000), 512MB nand flash(didn't find mapping so far) and 2MB data flash (mapped at 0xc0000000).
What I don't understand here:
- why there is a mem=64 in the bootargs? Isn't this supposed to be given as ATAG or DTB ?
- why is there a console given as argument when we pass the control to kernel? Is the kernel using the tty already configured by uboot?
- initrd vs rootfs. This is still not clear to me. I know initrd can be included in kernel as a block device or a separate image for which uboot has to pass address details to kernel (true?). Can we have a kernel without an initrd included + another file system, like this jffs2, from which the kernel will run rest of drivers? Actually I'm not able to understand full details of the file system used by kernel at boot. In this setup I have, there are 4 files: uImage, bootstrap, env.bin and jffs2 file system. So there is no initrd. How is this working? And how is the process of rooting the file system pointed in the above bootargs? In my understanding, the kernel should access first the jffs2 file system, then grab the image found in /dev/mtdblock1 and mount it. Perhaps my understanding is wrong. Actually this interaction between kernel and file system is what I seem not to understand. In the above bootcmd, the kernel is copied from nand to sdram then bootm jumps to it. But how does the kernel find the jffs at booting time? I see this output line during boot: VFS: Mounted root (jffs2 filesystem) on device 31:1.
In the board user guide I found this:
WARNING: Due to AT91SAM9261 chip errata booting from NAND flash is not supported.
...
512MB NAND Flash (seen in Linux as silicon drive).
- After compiling the kernel, I observed the System.map doesn't have all symbols. I checked the vmlinux and it's the same. Does anyone know why? Maybe the compiler was not configured properly?
Many thanks, Daniel.
Most of your questions can be answered by reading the Documentation that comes with your Linux source. Some key files are,
Please take a look through them as they will have information current to your version of Linux.
The 2.6.30 kernel pre-dates device trees for the ARM.
There are two mechanisms. The ATAGS is more flexible as it can specify several non-contiguous banks of memory. The idea is that boot code can probe the memory and provide it via ATAGS. That is the theory. It is often tough to do, so allowing a user to specify mem=64 is a lot easier to implement. If there are two board types, one with 64MB and one with 128MB, it is up to the user to provide a command line to use the extra memory.
Some devices have multiple serial ports. Some kernels may wish to use the 'u-boot' port for something else. HDSPA modem, printer, etc. The Linux kernel and the u-boot consoles may be different. That is a feature. I often use /dev/null as the console. Hardware is often stingy to give an extra serial port. Maybe you are lucky and your hardware people don't think software is free.
You may boot directly to a file system (rootfs), but all of the code and mechanisms for finding the code must be inside the Linux image. Even if they are (JFFS2/NAND), you may end up with a corrupt rootfs as NAND wears. The first 128MB of NAND is usually a higher quality. You may put a Linux with initrd here that is capable of repair of the main file system. For other boot devices, it may not be straight forward to boot the device and complex decisions can be made in an initrd image. Often the initrd take far less time to mount and you may perform some actions more quickly. Finally, you may load different modules and then lock module loading in the initrd.
You may use the rootfs directly. It is simpler to implement. The initrd is much more flexible and powerful. You may wish to transition from JFFS2 to Ubi/UbiFS. If you don't have an initrd, then this is pretty much impossible (at least much more difficult to implement).
The uImage may have an initrd attached to it. It is mounted as a ramdisk and after it unmounts (and
switch_root
to the new/final rootfs) the memory is free to use. However, your command line has no initrd info, so you probably don't have one.You have information to find the device;
root=/dev/mtdblock1
and you told it the file system type;rootfstype=jffs2
. The missing piece is theinit=/sbin/init
. You can read about it in the kernel-parameters.txt for your Linux. After the JFFS2 is mounted, the init code looks for a process to run. It is the parent process of everything and it will start to execute many different processes. Typically it is init, but you can specifyinit=/bin/sh
and you will just have a shell to start with. This can be a good way to develop an initrd image as you can test scripts with only one process running.The System.map is really only external functions and data. It does not include every function. In fact some functions may not exist due to in-lining.
I guess it is u-boot's job to handle this.