官术网_书友最值得收藏!

Booting your kernel

Booting is highly device-dependent, but here is an example using U-Boot on a BeagleBone Black and QEMU:.

BeagleBone Black

The following U-Boot commands show how to boot Linux on a BeagleBone Black:

U-Boot# fatload mmc 0:1 0x80200000 zImage
reading zImage
4606360 bytes read in 254 ms (17.3 MiB/s)
U-Boot# fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb
reading am335x-boneblack.dtb
29478 bytes read in 9 ms (3.1 MiB/s)
U-Boot# setenv bootargs console=ttyO0,115200
U-Boot# bootz 0x80200000 - 0x80f00000
Kernel image @ 0x80200000 [ 0x000000 - 0x464998 ]
## Flattened Device Tree blob at 80f00000
   Booting using the fdt blob at 0x80f00000
   Loading Device Tree to 8fff5000, end 8ffff325 ... OK
Starting kernel ...
[   0.000000] Booting Linux on physical CPU 0x0
...

Note that we set the kernel command line to console=ttyO0,115200. That tells Linux which device to use for console output which, in this case, is the first UART on the board, device ttyO0, at a speed of 115,200 bits per second. Without this, we would not see any messages after Starting the kernel ... and therefore would not know if it was working or not.

QEMU

Assuming that you have already installed qemu-system-arm, you can launch it with the multi_v7 kernel and the .dtb file for the ARM Versatile Express, as follows:

$ QEMU_AUDIO_DRV=none \
qemu-system-arm -m 256M -nographic -M vexpress-a9 -kernel zImage -dtb vexpress-v2p-ca9.dtb -append "console=ttyAMA0"

Note that setting QEMU_AUDIO_DRV to none is just to suppress error messages from QEMU about missing configurations for the audio drivers, which we do not use.

To exit from QEMU, type Ctrl-A then x (two separate keystrokes).

Kernel panic

While things started off well, they ended badly:

[    1.886379] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    1.895105] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0, 0)

This is a good example of a kernel panic. A panic occurs when the kernel encounters an unrecoverable error. By default, it will print out a message to the console and then halt. You can set the panic command line parameter to allow a few seconds before it reboots following a panic.

In this case, the unrecoverable error is because there is no root filesystem, illustrating that a kernel is useless without a user space to control it. You can supply a user space by providing a root filesystem either as a ramdisk or on a mountable mass storage device. We will talk about how to create a root filesystem in the next chapter but, to get things up and running, assume that we have a ramdisk in the file uRamdisk and you can then boot to a shell prompt by entering these commands into U-Boot:

fatload mmc 0:1 0x80200000 zImage
fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb
fatload mmc 0:1 0x81000000 uRamdisk
setenv bootargs console=ttyO0,115200 rdinit=/bin/sh
bootz 0x80200000 0x81000000 0x80f00000

Here, I have added rdinit=/bin/sh to the command line so that the kernel will run a shell and give us a shell prompt. Now, the output on the console looks like this:

...
[ 1.930923] sr_init: No PMIC hook to init smartreflex
[ 1.936424] sr_init: platform driver register failed for SR
[ 1.964858] Freeing unused kernel memory: 408K (c0824000 - c088a000)
/ # uname -a
Linux (none) 3.18.3 #1 SMP Wed Jan 21 08:34:58 GMT 2015 armv7l GNU/Linux
/ #

At last, we have a prompt and can interact with our device.

Early user space

In order to transition from kernel initialization to user space, the kernel has to mount a root filesystem and execute a program in that root filesystem. This can be via a ramdisk, as shown in the previous section, or by mounting a real filesystem on a block device. The code for all of this is in init/main.c, starting with the function rest_init() which creates the first thread with PID 1 and runs the code in kernel_init(). If there is a ramdisk, it will try to execute the program /init, which will take on the task of setting up the user space.

If it fails to find and run /init, it tries to mount a filesystem by calling the function prepare_namespace() in init/do_mounts.c. This requires a root= command line to give the name of the block device to use for mounting, usually in the form:

  • root=/dev/<disk name><partition number>
  • root=/dev/<disk name>p<partition number>

For example, for the first partition on an SD card, that would be root=/dev/mmcblk0p1. If the mount succeeds, it will try to execute /sbin/init, followed by /etc/init, /bin/init, and then /bin/sh, stopping at the first one that works.

The init program can be overridden on the command line. For a ramdisk, use rdinit=, (I used rdinit=/bin/sh earlier to execute a shell) and, for a filesystem, use init=.

Kernel messages

Kernel developers are fond of printing out useful information through liberal use of printk() and similar functions. The messages are categorized according to importance, 0 being the highest:

They are first written to a buffer, __log_buf, the size of which is two to the power of CONFIG_LOG_BUF_SHIFT. For example, if it is 16, then __log_buf is 64 KiB. You can dump the entire buffer using the command dmesg.

If the level of a message is less than the console log level, it is displayed on the console as well as being placed in __log_buf. The default console log level is 7, meaning that messages of level 6 and lower are displayed, filtering out KERN_DEBUG which is level 7. You can change the console log level in several ways, including by using the kernel parameter loglevel=<level> or the command dmesg -n <level>.

Kernel command line

The kernel command line is a string that is passed to the kernel by the bootloader, via the bootargs variable in the case of U-Boot; it can also be defined in the device tree, or set as part of the kernel configuration in CONFIG_CMDLINE.

We have seen some examples of the kernel command line already but there are many more. There is a complete list in Documentation/kernel-parameters.txt. Here is a smaller list of the most useful ones:

The lpj parameter is often mentioned in connection with reducing the kernel boot time. During initialization, the kernel loops for approximately 250 ms to calibrate a delay loop. The value is stored in the variable loops_per_jiffy, and reported like this:

Calibrating delay loop... 996.14 BogoMIPS (lpj=4980736)

If the kernel always runs on the same hardware it will always calculate the same value. You can shave 250 ms off the boot time by adding lpj=4980736 to the command line.

主站蜘蛛池模板: 乃东县| 大城县| 修文县| 保山市| 潜山县| 镇宁| 宝山区| 修文县| 宝坻区| 拜泉县| 平远县| 聂拉木县| 甘谷县| 手机| 金坛市| 新乡市| 荥阳市| 石楼县| 新乡县| 扬中市| 太仓市| 滦南县| 庆安县| 文昌市| 和田县| 阿拉善左旗| 东明县| 临高县| 靖宇县| 和龙市| 新巴尔虎左旗| 普陀区| 米脂县| 沂水县| 桐梓县| 福州市| 湖南省| 新河县| 阳江市| 黄大仙区| 滕州市|