文档库 最新最全的文档下载
当前位置:文档库 › 内核启动流程

内核启动流程


内核启动流程:
1. 处理/保存bootloader传入的参数 (r0,r1,r2, 在内存里设置的tag)

2. 创建页表, 使能MMU (从链接脚本可知内核的链接地址ko为0xc0008000, 它是虚拟地址)

3. 设置栈, 调用C函数 : b start_kernel

4. 加载一系列的驱动: flash, 串口, lcd, 鼠标, 键盘, usb ....
5. 挂接根文件系统
6. 启动应用程序


怎么编译内核?
----------------------------------------------------------------------------------------------------------------------
1. 配置内核
1.1 使用厂家提供的配置文件
1.2 使用内核里面默认的配置文件, 在它的基础上配置
1.3 从头开始,自己配置

2. 编译内核: make, make uImage


操作步骤:
1. tar xjf linux-2.6.22.6.tar.bz2

2. 打补丁:
cd linux-2.6.22.6
patch -p1 < ../linux-2.6.22.6_jz2440.patch

3. 配置
3.1 使用厂家提供的配置文件
cp config_厂家 .config
make menuconfig

3.2 使用内核里面默认的配置文件, 在它的基础上配置
find -name "*defconfig" | grep "2410"

make s3c2410_defconfig
make menuconfig

3.3 从头开始,自己配置
make menuconfig


4. 编译内核: make, make uImage

实验:
cp config_ok .config

make menuconfig # 把dm9000去掉,选上cs89x0

如果make menuconfig出错,说是找不到ncurse.h,要安装ncurse开发包:
tar xzf ncurses-5.9.tar.gz
cd ncurses-5.9
./configure --with-shared --prefix=/usr
make
sudo make install

修改Makefile:
arm-linux- 改为 arm-linux-gnu-

make uImage
如果最后说 mkimage not found,
从u-boot的tools目录下把mkimage复制到/bin目录去, 再执行 make uImage


arm-linux-gnu-ld -EL -p --no-undefined -X -o vmlinux -T arch/arm/kernel/
vmlinux.lds arch/arm/kernel/head.o arch/arm/kernel/init_task.o init/built-in.
o --start-group usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built
-in.o arch/arm/common/built-in.o arch/arm/mach-s3c2410/built-in.o arch/arm/
mach-s3c2400/built-in.o arch/arm/mach-s3c2412/built-in.o arch/arm/mach-
s3c2440/built-in.o arch/arm/mach-s3c2442/built-in.o arch/arm/mach-s3c2443/
built-in.o arch/arm/nwfpe/built-in.o arch/arm/plat-s3c24xx/built-in.o
kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/
built-in.o crypto/built-in.o block/built-in.o arch/arm/lib/lib.a lib/lib.
a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in
.o net/built-in.o --end-group .tmp_kallsyms2.o


内核代码分析:
1. arch/arm/kernel/head.S

// 判断该内核是否能支持这个CPU
bl __lookup_processor_type

// 判断该内核能否支持这个单板(machine)
bl __lookup_machine_type

// 创建页表
bl __create_page_tables

// 调用CPU相关的处理函数
add pc, r10, #PROCINFO_INITFUNC

// 上面的函数执行完后,跳到lr去(lr被设为"adr lr, __enable_mmu")
// 使能MMU

// 使能完MMU后,

跳到r13去(r13被设为__mmap_switched)
b start_kernel


start_kernel:
// 解析bootloader传入的参数
setup_arch(&command_line);

// 调用一系列的驱动程序
// 链接时,把一系列的驱动程序的函数放在一起
// 然后从头执行到尾

rest_init > kernel_init > do_basic_setup > do_initcalls

for (call = __initcall_start; call < __initcall_end; call++) {
result = (*call)();
}

__initcall_start = .;
*(.initcall0.init) *(.initcall0s.init)
*(.initcall1.init) *(.initcall1s.init)
*(.initcall2.init) *(.initcall2s.init)
*(.initcall3.init) *(.initcall3s.init)
*(.initcall4.in it) *(.initcall4s.init)
*(.initcall5.init) *(.initcall5s.init)
*(.initcallrootfs.init)
*(.initcall6.init) *(.initcall6s.init)
*(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;

驱动举例:
在include/linux/init.h里:
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __initcall(fn) device_initcall(fn)
#define module_init(x) __initcall(x);

module_init(s3c2410fb_init);

static initcall_t __initcall_s3c2410fb_init6 __attribute_used__ \
__attribute__((__section__(".initcall6.init"))) = s3c2410fb_init;



// 挂接根文件系统
start_kernel > rest_init > kernel_init > prepare_namespace > mount_block_root > do_mount_root
// bootloader传入命令行参数里有 root=/dev/mtdblock2
mount_block_root(root_device_name, root_mountflags);


// 执行应用程序
start_kernel > rest_init > kernel_init > init_post

sys_open((const char __user *) "/dev/console", O_RDWR, 0)
(void) sys_dup(0);
(void) sys_dup(0);

if (ramdisk_execute_command) { /* 命令行参数 rdinit=xxxx */
run_init_process(ramdisk_execute_command);
}

if (execute_command) { /* 命令行参数 init=xxxx */
run_init_process(execute_command);
}

run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");




文件系统:
内容应该有什么?
1. /dev/console
2. /sbin/init, /etc/init, /bin/init, /bin/sh 中某一个
3. 自己的应用程序
4. 配置文件
5. 库


对于嵌入式LINUX,有一个程序叫busybox, 它集成了init, ls, cp, cd等各种命令/程序

想了解配置文件,就要分析init程序, init程序有很多版本,有busybox的版本
在嵌入式LINUX里面,一般用busybox的版本



编译/体验 busybox
tar xjf busybox-1.18.5.tar.bz2

1. 配置
make menuconfig
为开发板设置编译器前缀
选择要编译的命令

2. 编译
make

3. 安装
make install

4. 体验:
在_install目录下, 执行:
ls -l ./bin
ls -l ./bin/busybox
./bin/busybox
./bin/busybox ls
./bin/ls





附:
1. 参数处理:

__setup("root=", root_dev_setup);

#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)



相关文档