我们这里将会介绍uboot的移植过程 我们以韦东山的uboot版本为材料 linux内核是3 版本进行讲解。
Uboot
下载下来uboot之后进行解压 然后我们需要知道底下的几个命令:
在readme中, 我们可以知道利用make XXX_config ()其中XXX是板子的命名)我们就可以建立这个板子的设置了。 我们的开发板是s3c2440 所以我们理应用的命令是make s3c2440_config 但是uboot现在不支持2440 他只是支持2410 所以说我们需要首先利用2410建立对2440的板子的支持。
那么既然使用make XX_config 来配置不同的板子, 在board.cfg 这个文件 可以查看到利用make XX_config 之后make file会调用某一个板子的信息
在这里我们可以发现这里面的每一个列的意思是:Target, Arch, CPU, Board, name, Vendor, SOC, Option.
请仔细阅读Readme 的file tree 我们复制smdk2410的所有文件给smdk2440. 我们需要复制的文件是:
- 在board/Samsung 中我们复制2410 文件夹 到2440 这样子我们就有了专门给2440芯片
- 在uboot/include/configs 我们可以复制smdk2410.h 到smdk2440.h
这样子我们基本上 就建立了一个基于smdk2440的uboot。
让我们编译一下 make smdk2440_config 把这个uboot烧到板子里面 我们会发现这里并不会启动板子。我们还是需要修改程序来使得这个uboot可以用。
所有的程序烧到板子上都必须首先配置如下的东西:
1. 时钟 //这样子我们就可以让程序在芯片上运转
2. 内存 //这样子我们就可以做代码重定位以及把所有的代码拷入内存
3. 串口 //这是为了看到打印出的信息
4. nandflash //一般我们会把代码拷入nandflash 当arm启动的时候 芯片会自动把前面4k拷贝到芯片内部的内存, 好让我们做代码重定位.芯片不能直接读取nandflash里面的内容。上电的时候芯片会读取自己内存里面0地址的地方而不会直接读取nandflash
5. nor flash //norflash 不容易写入内容但是可以直接读取内容,当芯片上电的时候芯片会指向norflash的0地址开始读取程序
6. 网卡:方便我们进行内核的下载
后面我会依照这个顺序依次的来说明如何修改uboot的代码。
第一阶段 时钟
我们需要看2440的芯片手册:
- LOCKTIME 这个是PLL lock time count 这个是当芯片复位之后必须有一定的复位时间来等待芯片的时钟稳定。这里我们取值是0xFFFFFFFF
- 根据这个table,把MDIV设置成0x5c PDIV 1 SDIV成为 1 (我们的input frequency是12Mh)输出的频率是400
- 另外我们还需要设置
设置这个表来得到FCLK和PCLK的值 给外设提供时钟
HCLK 是给芯片的AHB提供时钟 而且根据说明书他的最高速度是136Mhz 而我们的FCLK是400Mhz 那么我们HDVIN为10的时候HCLK 的速度就是100Mhz = FCLK/8 之后PDIVN最大的值是68Mhz 那么PDIVN为1的时候则PCLK是50Mhz = HCLK/2
所以CLKDIV = 0x05
由于2440 这个芯片必须加上非同步程序才能开启时钟 所以加上这句话
此时完成时钟的配置。
初始化内存
如手册上所示P192(PDF page) 5-1 内存需要挂接在BANK6 这个地方 所以内存的起始地址就是从0x30000000开始。 初始化内存是初始化时钟之后必须紧接着做的一步因为所有的c程序都需要栈 而栈是必须建立在这个内存初始化的基础上。我们的内存芯片采用的是两块EM63A165TS-6G 每一块都是32M字节 那么两个连在一起就是可以存储64M的内容。其中LADDR2连接到了A0的引脚就是说地址是16位的地址。也就是说每次位置都是以16位发生变化这个芯片是挂载到2440的内存控制器上 所以只是需要配置时序就好不用理会真正的协议。
在start.S 文件的第384行有一个函数叫做lowlevel_init.S 在这个里面有对sdram的初始化。
我们打开它来进行了解。
在这个目录下 /work/u-boot-2012.04.01_final/board/samsung/smdk2440 找到我们的lowlevel_init.S 在里面设置内存。
有几个变量需要我们去注意:
- Tacs
- Tcos
- Tacc = 4
- Delayed
我们首先确定SRAM的BWSCON
- [29:28]: 01 设置bank7到16 bit
- [25:24]: 01 设置bank6 到16 bit
- [17:16]: 01 设置网卡bank4 到 16bit
- [13:12]: 01 设置bank3 到16 bit
- [9:8]: 01 设置bank2 到16 bit
- [5:4]: 01 设置bank1 到16 bit
然后所有的从BANKCON0 ~ BANKCON5 都设置成0x700 这个是经验值
下面就是内存的时钟设置
首先我们用的是SDRAM所以我们的[16:15]位设置成11 是SDRAM
根据手册P18来设置这些
Tacs 设置成0 因为手册里面tIH只有1ns
其余的都设置成0
最后两位SCAN设置成01 = 9 bit
Trcd 设置成01 3 clocks
REFRESH:
[23]: enable the refresh function
[19:18]: 11 give 7 clocks
[7:0]: 1111 0100 (自己去计算)
BANKSIZE:
[7] Enable burst operation
[5] SDRAM power down mode enable
[4] SCLK is active only during the access
[2:0]: 001 64M/64M
MRSRB 6 : CAS latencty 3 clock
MRSRB 7 :CAS latency 3 clock
串口
我们必须把串口调出来才能知道内存是否配置正确。
在arch/arm/lib 里面有board_init_f.c 这个是start.S 里面引用的。
其中在init_sequence 这个数组里面存放了大部分的初始化信息其中就有一个board_early_init_f 这里面是原来设置时钟的地方我们可以暂时的把它删掉。
之后再serial_init 中的serial_init_dev 里面的_serial_setbrg 里面看到了get_PCLK()在其中的s3c24x0_get_base_clock_power()函数中get_HCLK() 里面发现了问题
其中我们的CONFIG_S3C2440根本没有被定义 所以我们必须首先定义这个变量 首先在
Include/configs/Smdk2440.h 定义CONFIG_S3C2440. 然后拿去编译。
编译之后 我们会发现如下的错误
这个是关于s3c2410_nand的问题我们查看之后发现(如下图)这个程序的结构体是定义了s3c2410_nand 之后才能用,我们现在不用管nandflash的事情所以说我们先可以不编译nandflash
这个文件是在/drivers/mtd/nand.c 文件, 我们需要找到drivers 文件夹下面的makeflie去去除这个文件的编译
那么在smdk2440.h里面去除这个define
我们在smdk2440.h中看到了这个宏是这么定义的
所以我们可以直接的把CONFIG_CMD_NAND这个宏定义直接去掉 再次进行编译。得出的结果:
发现是nand_info 没有被定义 那么我们现在可以直接的先把yaffs2的定义去掉,在.h文件中去掉config_YAFFS2
最后编译出来的是如下情形:
有个小问题就是为什么是405mz而不是400mhz 暂时未知 会在以后的时间加以改正。
已经找到原因请在s3c24x0/Speed.c 中修改如下代码:
#if defined(CONFIG_S3C2440)
if (pllreg == MPLL)
return 2 * 100 * (CONFIG_SYS_CLK_FREQ / (3 << 1));
把时钟的值固定下来就行了
至此第一阶段结束了。
第二阶段 代码重定位
- 支持nandflash启动
原来的代码在连接时加了-pie选项 这个选项会导致过于麻烦使得连接脚本里面多了(rel)(dyn)信息 ,使得程序非常大不利于从nand启动 从定位之前的代码应该小于4k。参考以前的start.S init.c 修改代码。 所以我们要要做的是把连接的地址定死启动的时候直接从flash中拷贝过去。
- 我们需要去掉 -pie
首先我们需要先初始化nandflash 让nandflash能够工作
初始化nandflash
我们使用的nandflash 是K9F2G08U0C, 把之前课程写过的nandflash的驱动放到这里面,把nand_init and nand_read 改成nand_init_ll and nand_read_ll 在makefile的COBJS 后面添加init.o
在init.c 中把一些内部的函数变成static的形式。
然后我们在回到start.s 里面 利用第223行的栈来对nandflash进行初始化
我们改好的程序如下:
其中我们的_TEXT_BASE 表示的的是我们的代码应该被考到那里去。 代码的前面第76行有了关于_TEXT_BASE 的定义 这个定义是告诉我们我们的TEXT 段是连接到哪里的。我们在这里改成0x33f00000, 因为我们的内存是64Mhz 我们内存的起始地址是从0x30000000到0x34000000. 我们的栈顶(0x30000000)到后面很大的一块地方是要放置新考进来的内核已经其他各种变量所以我们的uboot选择放在了内存的最后一片区域所以是放在了0x33f00000 到0x34000000 一共给了uboot 1M的空间 足够uboot的使用了。
所以下一步在smdk2440.h 里面更改CONFIG_SYS_TEXT_BASE 到0x33f00000
然后 start.s 更改之后的代码
之后是清除bss段:
之后就可以删除在board_init_f 中的relocate_code 函数了。
删掉所有关于relocate_code在start.S 里面的代码
注意后面的board_init_r这个函数需要id 和 dest_addr 这两个参数 其中这两个参数都是从board_init_f 的relocate_code 那里得出 所以我们需要更改board_init_f 让这个函数能返回这两个参数给board_init_r去用。
其中dest_addrs 就是程序的连接地址。
其中第一个参数id就是board_init_f 里面relocate的参数ID, 所以我们需要把board_init_f的改成return id的形式。
所以代码改成了:
下一步 修改Makefile 去掉-pie这个选项
修改arch/arm/config.mk 去掉-pie选项
修改连接脚本:
其中连接脚本是自动生成的!!! 所以当我们修改了连接地址之后 连接脚本自己也会有变化。找到arch/arm/cpu/u-boot.lds
把start.s init.c lowlevel.S 加到文件最前面
注意在board.c中 addr 要等于CONFIG_SYS_TEXT_BASE 这样子addr就知道重定位的地址了 我们手动给addrs 一个重定位的地址。
效果图:
支持norflash
首先我们看到我们的flash信息是 ***Failed*** 在源代码中查找这个信息看看是在哪里得到的:
Grep “Flash:” * -nR 发现在arch/arm/lib/board.c 505 行有这句话 所以去看是什么引起的这句话。当我们使用的nandflash的时候 肯定不可能在flash_init中返回正确的值。所以说我们在529行的hang哪里改成 如果找不到nandflash就变成nand_flash is 0 kb 去掉hang()函数。 去掉hang函数之后就可以向nandflash 代码运行
好,此时我们关注的是norflash 所以我们进入flash_init去看一下代码 为什么norflash识别不出来
打印一下调试信息 使能debug 发现ID号码可以被打印出来,那么就是说明时序是对的 但是我们发现程序后面有一个匹配的函数jedec_flash_match 里面有一个jedec_table 里面会有很多的norflash类型 显然我们自己的norflash 可能不在这里 需要我们自己去填写。
我们首先去看norflash里面读出的ID对不对。经过验证读出的设备ID是正确的 那么为什么还是识别不出 看起来是jedec_table 里面没有我们norflash的信息
这个数组里面的元素如下:
.mfr_id = 厂家ID
.dev_id = 型号ID
.name = 姓名
.uaddr = 解锁地址
.DevSize = 设备大小
.CmdSet =
.NumEraseRegions = 1, //norflash的擦出块假如norflash擦除的page都是一个size那么就是一个擦除区域 如果有不同的擦除的大小那么就是把它们都加起来 比如我们有三个128K 和四个64k那么我们就有2个擦除区域 一个是128 一个是64 我们的手册得知我们的擦除区域有4个 分别是16K *1 8K*2 32K* 1 64K* 31
Regions =
把每个块写进去。
我们的版本使用的是MT29LV160DB 我们在最后加一项我们自己的产品的型号程序如下:
烧写之后变成如下效果
我们发现其中Flash有一个error就是too many flash sectors 我们只要把smdk2440.h 里面的#define CONFIG_SYS_MAX_FLASH_SECT (19) 改成128 就行了。
下面介绍几个uboot里面运行的命令:
- cp.b 30000000 80000 10000 : 按照字节把30000000 里面的内容拷到 80000里面去 其中长度为10000
- cmp.b 30000 80000 10000 比较30000000 和 80000 开始0x10000 的字节的差异
- md.b display memory in byte.
在这里我们会发现我们的栈设置的有问题,栈的位置一直在0x3000f80这个地方离0x30000000太近了所以我们应该把栈设置的远离这个地方 因为这个地方是为了放置内核和新的uboot等code的.
所以我们的sp 在board_init_f 里面已经设置好了 但是需要我们用汇编语言给到sp中去详细的代码请看源码。
所以我们加上了在汇编中加入了base_sp 在c语言中我们把得到了的sp的值返回给base_sp
支持nandflash
如果想支持nandflash 首先需要把config_cmd_nand这个宏定义定义上去 然后进行编译看看出什么错误。
我们发现出现了在s3c2410_get_base_nand function中我们的一些结构体没有定 在第57行我们还是在用s3c2440_nand 结构体其实此时应该用的是s3c2440的结构体
我们的nand结构体的原理:
2440里面有一个nand的控制器
- 如果是当CLE是高电平的话传输的是cmd
- 如果ALE是高电平的时候传输的地址
- 如果CLE是低电平的话是是数据
我们拷贝一份drivers/mtd/nand/2410_nand.c 到2440_nand.c 然后修改makefile去让其编译2440_nand.c
在makefile第61行把s3c2410_nand.o 改成s3c2440_nand.o
在配置文件smdk2440中我们改成CONFIG_NAND_S3C2440 和 CONFIG_SYS_S3C2440_NAND_HECC
Nandflash 发信息的流程:
- 片选
- 发命令
- 发地址
- 发数据
- 判断状态
首先看s3c2440_nand.c里面的board_nand_init里面对nandflash进行初始化
然后我们在
我们这里的时间参数远远大于我们的理论值 所以不用改
后面我们在line146行发现这个S3C2410_NFCONF_EN是bit15 我们不需要所以我们先注释掉我们发现代码从146到149 并不适用于我们的2440 所以需要修改
而且我们需要把2410更改成2440
比如上图就应该改成s3c2440_nand 和 s3c2440_get_base_nand()
我们发现这个程序需要大改因为2440和2410不同我们需要改变代码,2440中cont 寄存器里面的第一位是片选 所以改成(1<<1)
在board_nand_init中我们需要初始化使能flash 初始化ECC禁止片选
分析流程:
- 先看单板初始化:设置nand结构体,设置片选
- 看nand_scan 函数
下面我们看nandscan
在nand.c中(nand.c 是不跟硬件相关的函数)里面有nand_scan 函数
Nandscan是一个nandflash识别的函数
在nand_scan_ident中:
- 设置nand_set_defualts 函数:
- Nand_get_flash_type
发出复位的命令
发出读ID的命令
之后 读厂家ID读设备ID
我们发现之前的selectchip是有问题的
如上图所示
所以说我们需要自己完成chip_select
而且我们需要重新重构hwcontrol
然后烧录到板子当中用以下的命令来做测试
其中我们能看到NAND: 256 MiB 就说明已经被识别出来了
下面我们就要进行第三个阶段 网卡的移植, 这样子我们就能用过网卡快速的下载uboot和内核了。
第三部分 网卡的移植
在这里我们需要利用网卡的能力去下载内核和新的uboot程序 所以现在我们得先把uboot里面的网卡启动起来 我们用的网卡是DM9000, 在uboot中已经写好了。我们在driver/net 目录下面的makefile中看看是否已经编译进去了DM9000
在这里我们发现我们既定义了CS8900也定义了dm9000 所以说我们需要去掉CS8900这个网卡 找到smdk2440.h 然后去掉CONFIG_CS8900 加上CONFIG_DRIVER_DM9000
我们的网卡是一个内存协议的芯片所以他是接在内存的控制器上。
所以对于DM9000来说我们需要做的是:
- 设置内存控制器:时序和位宽
- 确定访问地址
我们的网卡是接到了CS4 所以我们就可以确定基地址是0x20000000
在DM9000中有IO地址还有DATA地址 在硬件设计中 Addr2接在了cmd引脚上面所以说是由addr2引脚控制是发送cmd还是发送data
那么就是说我们的(1<<2)左移2位 控制着芯片输出IO还是data 所以说设置为:
#define DM9000_DATA (CONFIG_DM9000_BASE + 4)
参考原理图我们会发现我们的网卡只有address2 连接在了cmd上面说明了输出DATA的地址是在(CONFIG_DM9000_BASE + 4)
而IO是在CONFIG_DM9000_BASE 上面
网卡的位宽是16 所以我们得把bank4相应的寄存器 设置成16位
如上图下载之后会出现no Ethernet found 所以说还是有问题, 我们根据这句话找到是谁触发了这句话
我们进入这个文件看看究竟是怎么回事儿
在eth.c 的367行:
发现了这句话 我们再看看前面的那个“Net”是怎么打印出来的
发现在board.c下面打印了这句话 说明了board.c对网卡进行了初始化。
应该是eth_initialize 这里出了问题
我们发现这里根本没有跟DM9000进行初始化 所以需要更改
再次进行烧录
此时发现网卡已经被显示出来了。
我们做做实验看看网卡能不能用
使用工具是tftp
我们首先把tftp文件夹下面存放.bin 文件
然后我们需要更改板子上面的IP MAC IP
Set ipaddr 192.168.20.3
Set ethaddr 00:0c:29:22:cc:2d (这个是mac地址)
Ping 192.168.20.4
得到如下结果
我们用tftp试试能不能下载文件
设置 serverip
Set 192.168.20.4 (就是PC的IP)
使用命令tftp 30000000 uImage 去下载文件夹中的uImage 请注意我们必须把文件放入到tftp这个软件的文件夹下面!!
下载之后用bootm 30000000去启动设备
发现可以启动 证明我们的网卡移植成功!!
第四部分 设置环境参数和变量
环境变量是存在flash的某个地方中,当启动的时候系统会读用户给的参数如果无效就使用默认的参数这些参数就是默认的环境参数和变量它是在代码中写死了。
我们看板子里面的信息有“warning bad crc use default environment”
首先搜索using default environment. 我们在common/env_common.c 这个文件中找到了这句话
然后我们找到了default_environment 这个数组:
在这里就是定义了我们所有的默认参数
首先看到的是config_bootargs 这个是传给内核的参数
我们在smdk2440.h里面定义一下:
我们的规划是:
- 最前面放uboot
- 中间放参数
- 后面放内核
- 最后放文件系统
console=ttySAC0 root=dev/mtdblock3: 表示我们用串口0 打印信息 然后文件系统在第三个block
第0个block放uboot
第一个放参数
第二个放内核
第三个放文件系统
内核会根据这里的默认的环境变量信息来确定自己如何启动
#define CONFIG_BOOTCOMMAND "nand read 30000000 0 0xabc 0x200000; bootm 30000000"
Nand read 读到30000000 从nand的abc地址开始读 读2Mb长度 我们现在没有规划好位置所以长度先随便写, 然后从30000000开始运行
更改ip相关内容
然后我们裁剪一下这个uboot把不要的都去掉
然后我们设置自己的分区:
注意我们下面烧写还是烧到norflash 但是我们也定义了支持nandflash
我们这在uboot中打 ?save 我们就能知道他是用的哪个函数
我们查出这个函数是saveenv
我们发现里面用在nandflash中的宏函数是CONFIG_ENV_IS_IN_NAND
在env_nand.c 中我们找到saveenv 里面有一个CONFIG_ENV_OFFSET的宏定义这个就是我们的环境变量的偏移地址。 我们的环境变量的起始地址在0x40000 所以应该设为这个变量
我们还需要知道大小#define CONFIG_ENV_SIZE 注意这个值必须是128K的整数倍。
下面是定义CONFIG_ENV_RANGE 这里我们设置和CONFIG_ENV_SIZE相同
利用protect off all unlock flash的保护 然后
Erase 0 3ffff
Cp.b 30000000 0 40000
然后重新启动设备。
之后我们需要利用mtdpart这个命令来设置分区
这么设置才能进行分区
然后我们发现每次我们想要用这个分区我们都是要执行一次mtdpart default 所以我们可以在代码里面写入default这样子我们就不能每次都手工的执行这条命令了。
加入run_command 这个命令
然后我们就能看到分区了
此后我们需要把之前的CONFIG_BOOTCOMMAND 改成kernel
下载内核:
tftp 30000000 uImage;nand erase.part kernel;nand write 30000000 kernel
第四阶段完成
第五阶段 制作yaffs
Yaffs JFFS2 这两文件的区别:
- JFFS2: 启动速度慢 但是适合于nor和nandflash
- YAFFS2专门为了nandflash制作的文件系统。启动速度比JFFS2快
在测试之前请确保已经加载了uImage
首先我们先试试已经提供给的jffs2
命令 tftp 30000000 fs_mini_mdev.jffs2;
nand erase.part rootfs;
nand write.jffs2 30000000 0x00260000 5b89a8 (文件的长度)
对于JFFS2的启动参数应该是改为
set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
然后 命令boot
这样子我们的内核和root就都写入了单板 现在板子里面就能跑Linux内核的系统了。
下面让uboot支持我们的Yaffs系统:
烧写新的uboot
tftp 30000000 u-boot.bin;protect off all;erase 0 3ffff;cp.b 30000000 0 40000
烧写的命令是
tftp 30000000 fs_mini_mdev.yaffs2;nand erase.part rootfs;nand write.yaffs 30000000 260000 889bc0
set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=yaffs
我们发现在nand_util.c 应该改成OBB_MTD_RAW 后面的的if(!rval) 改成if(rval)
然后就可以运行了(这里我的板子发现即使用了做好的uboot还是不行 估计是哪里出现了问题 还在查找)
如何制作补丁:
使用diff –urN [旧文件] [新文件] > [补丁文件]
如何打补丁?
Patch –p1 <[这里是补丁文件]
P1: 如果已经在这个文件夹中了 就省略这个文件夹
第二部分 内核的移植
我们这个版本是linux 3.4.2.
内核的启动过程:
从nand flash 把内核传到内存,设置参数,里面有内存的起始地址大小,字符串命令行参数。调用内核r0 里面存入0 r1里面存入板子的信息(机器ID) r2 里面存有参数的存放地址
目的是为了启动应用程序。
内核需要装载驱动程序 挂接根文件系统 启动应用程序。装载驱动程序 解析tag参数。
根据R1选择判断能否支持该机器调用跟机器相关的初始化函数
也就是说根据不同的板子初始化不同的函数。
在uboot中确定开发板的ID 然后内核会把从内存中得到的开发板的ID和自己本身的开发板进行比对 如果是一致的则就调用这个开发板的底层程序 比如串口等等。
我们下载完内核之后编译一下。
首先我们tar xjf linux-3.4.2.tar.bz
然后修改makefile 让他支持arm-linux-gcc
我们需要的GCC版本是:4.4.3
在arch/arm/configs 里面我们能看到所有关于arm不同板子的配置
Make s3c2410_defconfig
我们用了2410的配置但是在最后生成的.config中我们能得到2440的板子
Make uImage 编译内核
然后烧到nandflash中去 我们发现里面是乱码说明了可能是时钟的原因。
但是之前我们看一下uboot里面设置的默认的机器id是什么
我们发现我们这里写的还是smdk2410 而不是smdk2440
在uboot中我们没有发现2440的板子的machineID 但是在linux里面应该是有的 但是如果找到呢 我们可以在uboot中随便设一个很大的machineID然后linux会提示我们什么板子ID是可以用的在里面我们就可以找到2440的板子的ID号码了
然后我们就可以重新的set machId到16a了 或者也可以在uboot里面直接改过来。
在此我们就先不改了 而是利用set machid去改
Set machid 16a
但是此时我们还是打印出乱码 那么就是说明我们应该去改usart的时钟了查看内核的代码:
这里的时钟应该改成12Mhz
然后还要设置set bootargs console=ttySAC0,115200 root=/dev/mtdblock3
就可以实现linux的移植了。
但是当我们写入nandflash在重新启动的时候发现了他还是crc 没通过 原因是因为我们的uImage 太大了所以我们后面会做裁剪和补丁。
制作根文件系统和修改内核分区
我们下载内核的时候发现分区不对
所以说第一步我们要把分区弄对:
Grep “boot Agent” * -nR
我们在arch/arm/mach-s3c24xx/common-smdk.c 里面找到这个boot Agent.我们开始对他修改
这里我们需要改成和uboot的分区是一样的。
下面移植busybox
我们选用的是busybox1.7。0
首先我们先进行busybox的编译
首先make menuconfig
添加cross compile: arm-linux-
然后编译。
创建一个新的文件夹(fs_mini_mdev_new)用make install CONFIG_PREFIX=../fs_mini_mdev_new 把文件安装到这个文件夹里面。
有如下的东西就说明已经安装好了:
之后我们要在这个文件里面安装c库来支持这些文件
首先我们先看一下我们的交叉工具编译链在哪里 因为我们要烧到arm的板子上所以我们需要arm的c库来支持
echo $PATH
我们看到了这个库 这个库就是我们的arm-linux-gcc 存放自己的C库的地方/usr/local/arm/4.3.2/bin
我们进入这个这个地址/usr/local/arm/4.3.2/ 然后使用find –name lib 去查看我们到底有多少的库我们发现
其中我们的armv4t和armv4t/usr/lib 这两个库都是应该考到我们的文件夹中的
我们在fs_mini_mdev_new 底下创建一个库lib然后把上面两个文件夹的.so 文件都考入这个lib里面
命令是:cp arm-none-linux-gnueabi/libc/armv4t/lib/*so* /work/fs_mini_mdev_new/lib –d
mkdir -p /work/fs_mini_mdev_new/usr/lib
cp arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /work/fs_mini_mdev_new/usr/lib/ -d
之后要构造etc目录和dev目录
后面我们需要根据韦东山的视频来创建etc目录 我们会在后面把这块补上
在busybox启动之后 最开始执行的就是sysinit:/etc/init.d/rcs 这个脚本在这个脚本里面
造好etc之后 创建dev目录:
上电后执行initab里面的rcs 的mdev –s 他就会创建dev目录里面的内容 但是我们要先有两个字符型设备 null 和console
创建一个dev文件夹 然后
Mknod dev/console c 5 1
Mknod dev/null c 1 3
创建两个设备的节点
然后创建mkdir mnt proc tmp sys root这些目录
之后制作Jff2映像文件
这个命令是在可以执行mkfs的地方执行的
mkfs.jffs2 -n -s 2048 -e 128KiB -d ../fs_mini_mdev_new/ -o fs_mini_mdev_new.jffs2
然后烧写到板子里面去
其中烧写那一步是nand write.jffs2 30000000 260000 $filesize
然后烧写内核发现了如下的错误:
这个exitcode是非法指令 ,这是因为我们使用的是eabi接口
我们必须要在编译内核的时候加上这个eabi接口的定义才行。
什么是eabi接口?
可执行成应用程序的二进制接口 我们会在以后来查看到底是什么意思
但是现在我们需要把这个接口加上 在内核的的配置里面加入eabi接口
在这里添加上eabi接口
再次进行编译 烧写 看看这次行不行
Linux 启动成功!
下一个阶段: linux 支持yaffs系统。
移植Yaffs
我们去官网下载yaffs的库 然后读readme 发现了打补丁的命令:
Cd work/yaffts2
./patch-ker.sh c m [linux 目录] /work/linux3.4.2
在linux下make menuconfig 选中支持Yaffs 然后编译内核
发现出现了问题
我们来分析yaffs的代码。
发现大部分的代码都是没有加下划线 但是其中有一个是函数没有声明。把他改成d_make_root
改了错之后我们的内核就支持了Yaffs的系统 然后我们把这个内核烧录进板子 然后制作yaffs的映像文件 在我们的nfs_root里面有下载好的工具 直接执行下面的命令:
mkyaffs2image ../fs_mini_mdev_new fs_mini_mdev_new.yaffs2
制作成功之后 我们就烧写进去
烧写yaffs
Nand write.yaffs 30000000 260000 $filesize
set bootargs console=ttySAC0,115200 root=/dev/mtdblock3
之后发现了一个bug在
Driver/mtd/nand/nand_util.c line 518
添加了这一行之后
重新加载uboot 然后重新下载yaffs 和内核 最终就可以把内核移植进去了:
最后一个阶段:
剪裁linux内核
最后阶段 剪裁linux内核
我们发现我们的uImage 太大了 所以我们需要裁减一下
如图超过了2M
我们利用make menuconfig 去裁减这个内核
我们也可以根据输出的启动信息来去掉无用的信息
我们的新的uImage叫做uImage_new 烧进去看一下
至此 linux 从uboot到内核移植 全部完成!!!