|
bootloader引导内核
1、把内核读入内存
2、设置参数【TAG参数】
3、启动内核 R0寄存器=0 R1=机器ID R2=参数存放的地址
参考自己写bootloader
int main(void)
{
void (*theKernel)(int zero, int arch, unsigned int params);
volatile unsigned int *p = (volatile unsigned int *)0x30008000;
/* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口 */
uart0_init();
/* 1. 从NAND FLASH里把内核读入内存 */
puts("Copy kernel from nand\n\r");
nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
puthex(0x1234ABCD);
puts("\n\r");
puthex(*p);
puts("\n\r");
/* 2. 设置参数 */
puts("Set boot params\n\r");
setup_start_tag();
setup_memory_tags();
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
/* 3. 跳转执行 */
puts("Boot kernel\n\r");
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
/*
* mov r0, #0
* ldr r1, =362
* ldr r2, =0x30000100
* mov pc, #0x30008000
*/
puts("Error!\n\r");
/* 如果一切正常, 不会执行到这里 */
return -1;
}
内核:你目的是启动运用程序
1、根据R1寄存器的值来确定内核是否支持该机器[或者说是CPU],如果支持,调用该体系的初始化函数进行初始化
2、解析TAG参数
3、装载驱动程序,比如flash,网卡等
4、挂接根文件系统
5、启动运用程序
A、不同的开发板接的外设不一样,比如我们要使用串口打印信息,但开发板选中的晶振不一样,在初始化uart时
也是不一样的,比如接的网卡等都不一样,初始化函数是不同的,所以,我们需要修改初始化函数
移植过程:
1、解压内核
tar xjf linux-3.4.20.tar.bz2
2、配置内核[可以参考书籍“嵌入式Linux完全开发手册”]
a.修改makefile
vim Makefile
修改
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
b.选择默认的配置
查找一下有哪些默认配置
find -name "*defconfig"
有一大堆的默认配置,我们可以进去这个目录看一下
cd ./arch/arm/configs
- -支持mini2440了
看下2440有哪些
ls *2440*
看2410
2410更加全面一点
c.make s3c2410_defconfig [ 配置 ]
生成了.config文件,进去看下
支持这些板子
d.make uImage
e.把生成的uImage下载到板子32000000,然后启动看效果
nfs 32000000 192.168.1.114:/root/work/system_of_new/linux-3.4.20/arch/arm/boot/uImage
注:你得启动nfs服务才能执行这个命令
f.bootm 32000000
看效果
出现一大堆的乱码
g.原因:是传入的机器ID不对,得修改u-boot
我们知道u-boot启动内核的命令是bootm,那么我们就延着bootm追查下去,bootm命令是在cmd_bootm.c文件中实现的
,那么我们这里找到U_BOOT_CMD,在找到bootm命令,看它是怎么调用的
看到bootm调用do_bootm,我那我们进去do_bootm中看它是怎么启动内核的
看到boot_os[i] 这个数组,
这个数组中定义了体系架构启动内核,我们进去看看
第一行就看到do_bootm_linux,进去看看,在这个函数中看到,它调用boot_jump_linux
再进去看看
呐,这就是调用到机器ID了,
从这个函数知道,machid可以从环境变量中获得,没有的话执行默认的machid = gd->bd->bi_arch_number
我们追查bi_arch_number看是否有定义
我们查到,在smdk2410.c中有定义
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
它的值是193,这是2410的机器ID,而我们的是2440,所以,我们要修改这个宏。但从上面得出,机器ID可以从环境变量中获得,我们可以试验一下
h.uboot默认的machid gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
环境变量中获得的machid
s = getenv("machid");
如果s = getenv("machid")获得成功,则使用它,否则,使用默认的。
那么,我们可以设置一下machid,现在,我们使用的是193,内核中就根据这个193调用它的初始化函数,
那内核是怎么找到对应的机器呢?
看看内核代码
ls arch/arm/
进入这个目录 cd /arch/arm
find -name "mach*.o"
这些文件都被编译进去内核,从这些文件看出,我们编译的这个Linux.3.4.20支持很多种单板,可以测试一下
在uboot设置机器id: set machid 2343 【 随便设】 然后save
Using machid 0x2343 from environment 从环境变量获取machid
Error: unrecognized/unsupported machine ID (r1 = 0x00002343).不支持或不认识的machid
Available machine support: 可用的ID /* 这个编译的内核支持的单板太多了,导致内核非常大,所以还需要裁剪 */
既然是不识别或支持machid那就用个可识别的呗。
使用后
乱码
上面显示的是一些结构体来的,比如smdk2410,看它对应的文件是mach-smdk2410.c,他是根据这个数值[193或者是c1]来找到这个结构体的
这个结构体定义如下
展开这个宏
就会得到相应的信息,具体去inlcude/asm-arm/mach-types.h中查看
i.set machid 16a save /* mach-smdk2440.c */
下载内核启动
看结果结果
依然是乱码,有可能是串口波特率的问题
使用mini2440的机器id
set machid 7CF //mini2440 mach-mini2440.c
设置下串口波特率
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3
再次尝试
启动成功
set machid 16a save /* mach-smdk2440.c */
set machid 7CF //mini2440 mach-mini2440.c
这两个函数的差别
它的晶振使用的是16934400,我们板子用的是120000000,所以导致了我们启动内核时会出现乱码,再看下mini2440的
所以,串口乱码的问题已找到,那么,第一步就算完成了:串口能够输出信息
************************************************************************************************
第二步:修改分区表,制作新的文件系统
根据串口打印出来的信息进行修改
在源代码中搜索"Boot Agent"
grep "\"Boot\ Agent"\" * -nR
那我们在arch/arm/mach-s3c24xx/common-smdk.c中看一下/* common通用嘛 */
这就是分区表,我们修改一下,名字不重要,重要的是设置的大小
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"
-----------------------------------------------
按照这样的来写
MTDPART_OFS_APPEND /* 表示当前分区紧接着上个分区 在mtd_partition结构体中定义 */
MTDPART_SIZ_FULL /* 表示当前分区大小为剩下的flash空间 在mtd_partition结构体中定义 */
修改后编译下载启动
至少分区已经出来了,名字没显示,是不是没有烧写文件系统的原因?
那就烧写文件系统进去看看
烧写文件系统
nfs 32000000 192.168.1.114:/root/work/system_of_new/linux-3.4.20/arch/arm/boot/uImage
tftp 30000000 fs_mini_mdev.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 [文件的大小]
bootm 32000000
No filesystem could mount root, tried: ext3 ext2 cramfs vfat msdos iso9660 romfs
不支持yaffs2文件系统,但应该支持jffs2文件系统了,搜索一下.config看看有没有编译进去
搜索YAFFS2是没有的
烧写jffs2文件系统看看
tftp 30000000 fs_mini_mdev.jffs2
nand erase.part rootfs
//nand write.jffs2 30000000 260000 [文件的大小] 这个下载的大小已经有个环境变量保存着了。$filesize
nand write.jffs2 30000000 260000 $filesize
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2
nfs 32000000 192.168.1.114:/root/work/system_of_new/linux-3.4.20/arch/arm/boot/uImage
bootm 32000000
/* 这个是使用machid 为16a的状况 */
/* 这个是使用machid 为7cf的状况 */
文件系统挂接成功,但貌似还是有问题,终端开启不了。
发现文件系统已经挂载上去了,该文件系统是使用3.4.5的交叉编译器编译的文件系统,是不是交叉编译器的问题呢
在以上的分区表设置是以machid为前提的,我们做这些事情是选择以machid为16a设置【也就是smdk2440】,
但是,如果我们换了别的machid,比如说7CF【mini2440】的。那又得修改相应的文件
制作新的文件系统
使用busybox的版本是1.20,先make menuconfig,在setting中,制定交叉编译器
然后make
安装到/root/work/transplant/rootfs_mini_mdev_new
mkdir bin dev etc lib proc sbin sys usr mnt tmp var
mkdir usr/bin usr/lib usr/sbin lib/modules
1、安装busybox,不会看README文件
make install CONFIG_PREFIX=[要安装的路径] CONFIG_PREFIX
make install CONFIG_PREFIX=/root/work/system_of_new/rootfs_jffs2
2、创建设备文件
cd dev/
mknod -m 666 console c 5 1
mknod -m 666 null c 1 3
cd ..
3、安装/etc
tar -xvzf etc.tar.gz -C /xxx/rootfs
4、安装glib库
cp /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /root/work/system_of_new/rootfs_jffs2/usr/lib -d -p
cp /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib/*so* /root/work/system_of_new/rootfs_jffs2/lib -d
/* -d选项就是说原来是什么文件,拷贝过去也是什么文件 */
5、制作jffs2文件系统
mkfs.jffs2 -n -s 2048 -e 128KiB -d rootfs_jffs2 -o rootfs.jffs2
(1)解压zlib-1.2.3.tar.gz
tar zxf zlib-1.2.3.tar.gz
cd zlib-1.2.3
./configure --shared --prefix=/usr
make
make install
(2)编译mtd-utils-05.07.23
tar zxf mtd-utils-05.07.23
cd mtd-utils-05.07.23/util
make
make install
烧写
nfs 30000000 192.168.16.101:/root/work/transplant/fs_mini_mdev_new.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 0x00260000 $filesize
启动内核
还是有问题,看内核
搜索一下exitcode
do_exit()
SIGILL
SIGILL 信号是cpu在发现非法指令之后发出一个异常,然后由负责处理该异常的内核的ISR对含有这个非法指令的进程发出的。程序收到这个信号,一般就是报 告 illegal instruction 错误信息。
重新配置内核,加上EABI选项,上面说启动不了init,把机器ID改为16a就行了。这问题找了很久,貌似是mini2440的machid不行
加上后成功
6、制作yaffs2文件系统 参照文件系统的构建文档
1. 获得源码
git clone git://www.aleph1.co.uk/yaffs2
怎么使用呢,看REDME
2. 打补丁
cd /root/work/transplant/yaffs2
./patch-ker.sh c m linux-tree 比如 ./patch-ker.sh c m /root/work/transplant/linux-3.4.20
做完之后内核中就有了yaffs文件
3. 配置内核支持YAFFS
make menuconfig
4. 编译、使用uImage
出现错误/* 错误从第一个开始解决 */
分析yaffs源码
上面的错误说mtd_info没有这些成员,那么我们去这个结构体中看是否有没有
发现是有的
但在下面添加了一个下划线
还需注意一个函数,d_alloc_root(inode)内核已经不使用了
root = d_make_root(inode);//d_alloc_root(inode);
那怎么解决?
1.搜索一下d_alloc_root 发现在内核里已经改变了
Jun 1999 2.3.6 d_alloc_root use changed/* super.c */
2.既然没有了,那看看root是怎么用的
sb->s_root = root;
搜索s_root
sb->s_root = d_make_root(root_inode);
sb->s_root = d_make_root(root_i); /* jffs文件系统用的 */
别人是这么用的
5. 制作、烧写yaffs映象
mkyaffs2image rootfs rootfs.yaffs2
u-boot:
nfs 30000000 192.168.1.114:/root/work/transplant/fs_mini_mdev_new.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 460000 $filesize
6.启动内核
nfs 32000000 192.168.1.114:/root/work/system_of_new/linux-3.4.20/arch/arm/boot/uImage
bootm 32000000
挂载是挂载上去了,但是没成功。
7.解决问题
第6步没成,用替法产找问题问题
(1)u-boot有问题
换上u-boot1.16尝试
tftp 30000000 u-boot.bin (该uboot是1.16)
nand erase.part u-boot
nand write 30000000 u-boot
nfs 30000000 192.168.1.114:/root/work/transplant/fs_mini_mdev_new.yaffs2
nand erase rootfs
nand write.yaffs 30000000 260000 $(filesize)
nfs 32000000 192.168.1.114:/root/work/transplant/linux-3.4.20/arch/arm/boot/uImage
bootm 32000000
成功了,那就是u-boot有问题,查看u-boot源码
进入cmd_nand.c
do_nand
看到.yaffs
进入nand_write_skip_bad
添加&&!(flags & WITH_YAFFS_OOB) /* nand_util.c */
need_skip = check_skip_len(nand, offset, *length);
if (need_skip < 0) {
printf ("Attempt to write outside the flash area\n");
*length = 0;
return -EINVAL;
}
/* 这里需要改一下,添加&&!(flags & WITH_YAFFS_OOB)但是我板子不添加也是可以的 */
if (!need_skip && !(flags & WITH_DROP_FFS)&& !(flags & WITH_YAFFS_OOB)) {
rval = nand_write (nand, offset, length, buffer);
if (rval == 0)
return 0;
现在测试我的板子不修改也是可以的,如果不行再修改
重新烧写uboot
(2)yaffs有问题
裁剪内核
1.查看内核有多大
-rw-r--r--. 1 root root 2492272 4鏈 29 00:48 arch/arm/boot/uImage
非常之大
2.裁剪
make menuconfig
挑选不需要的去掉。怎么挑选呢,
vim .config
看看哪些板子不需要
这样做还是太麻烦,我们可以把内核烧写进去,看打印信息,然后修改
裁剪不到2m,那就修改分区呗
8.移植驱动程序
怎么移植?
1.编译出错,解决错误,有哪些错误?
头文件不对,改名或去掉
宏不对,改名使用新宏
有些函数没有了,改名,使用新的函数
|
|