18.17 U-Boot+内核移植
18.17.1 移植U-Boot-2012.04.08
1.下载、建立source insight工程、编译、烧写、如果无运行分析原因。
$ tar xif u-boot-2012.04.01.tar.bz2 $ cd u-boot-2012.04.01 $ make smdk2410_config $ make ERROR【错误原因:gcc版本低】 $ arm-linux-gcc -v [gcc version 3.4.5] 更新gcc步骤:解压到根目录 $ sudo tar -xjf arm-linux-gcc-4.3.2.tar.bz2 -C / $ ls $ usr $ echo $PATH查看gcc执行路径 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games: /work/tools/gcc-3.4.5-glibc-2.3.6/bin" $ sudo vi /etc/environment【在路径后增加:/usr/local/arm/4.3.2/bin】 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/4.3.2/bin" :wq sudo reboot 重启系统,更新gcc后,即可编译成功。烧写uboot.bin后,程序不运行!
2.分析u-boot:通过连接命令分析组成文件、阅读代码分析启动过程。
需要做的事:
1)初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
2)如果BootLoader比较大,重定位到SDRAM
3)把内核从NAND FLASH读到SDRAM
4)设置“要传给内核的参数”
5)跳转执行内核
$ arm-linux-objdump -D u-boot > u-boot.dis反汇编
代码中:DECLARE_GLOBAL_DATA_PTR定义一个r8寄存器变量
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
2.1 set the cpu to svc32:设置CPU为管理模式
2.2 turn off the watchdog
2.3 mask all IRQs by setting all bits in the INTMR - default:屏蔽所有中断
2.4 /* FCLK:HCLK:PCLK = 1:2:4 *//* default FCLK is 120 MHz ! */设置分频时钟比例
2.5 Set stackpointer in internal RAM to call board_init_f设置内存控制器
2.6 Set up the stack call C function:调用C函数,设置栈
2.7 call init_sequence:调用(函数数组)里的各个函数,初始化设备
2.7.1 board_early_init_f:设置系统时钟,设置GPIO端口
2.8 relocate_code(addr_sp, id, addr); :C调用asm;重定位代码,调用此函数时,重新修改了栈
addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;//0x3400,0000
addr-4k=0x33FF,F000
addr &= ~(0x10000 - 1);//0xFFFF清掉最低16位,0x33FF,0000
addr -= gd->mon_len;//697k/0x33FF,0000-0xae4e0(反汇编找到的)=33F41B20
addr &= ~(4096 - 1);//33F41B20清低12位=>0x33F4,1000
2.8.1 从NOR FLASH把代码复制到SDRAM:
2.8.2 程序的链接地址是0,访问全局变量、静态变量、调用函数时是使“基于0地址编译得到的地址”
现在把程序复制到SDRAM
需要修改代码,把“基于0地址编译得到的地址”改为新地址
2.8.3 程序里有些地址在链接时不能确定,要到运行前才能确定;fixabs
2.9 清除bss
2.10 调用board_init_r函数:第二阶段。应该再次设置sp
可以修改配置文件定义CONFIG_S3C2440
3. 修改U-Boot代码
3.1 建smdk2440单板
cd board/samsung
cp smdk2410 smdk2440 -rf
cd ../../include/configs/
cp smdk2410.h smdk2440.h
新建smdk2440单板规则
grep "smdk2410" -nR
修改boards.cfg:
仿照
smdk2410 arm arm920t - samsung s3c24x0
添加
smdk2440 arm arm920t - samsung s3c24x0
3.2 烧写实验:绝对不会成功的……哈哈哈
3.3 调试:【1.内存2.时钟】
a. 阅读代码发现不足:U-Boot里先以64M的时钟计算参数来设置内存控制器,但是MPLL还未设置
处理方法:把MPLL的设置放到start.s里,取消board_early_init_f里对MPLL的设置
编译出来的U-Boot很大,可以先烧写旧的U-Boot到nor,然后用这个U-Boot来烧写新的U-boot
用原来的方式设置MPLL和内存lowevel_init.S
3.4 查看串口波特率的设置,发现在get_HCLK里没有定义CONFIG_S3C2440
处理方法:include/configs/smdk2440.h:
//#defineCONFIG_S3c2410
#define CONFIG_S3C2440
编译有错误,根据MakeFile查找到宏后,去掉//#define CONFIG_CMD_NAND
3.5修改U-Boot支持NAND启动
原来的代码在链接时,加了-pie选项,使得u-boot.bin多了 *(.rel*)、*(.dynsym)信息
程序特别大,不利于从NAND启动代码(重定位之前的代码应该少于4k)
1.把链接地址定死,直接复制
2.导致了程序必须有地址段,程序远远超过4k;代码庞大,程序复杂
3.5.1 链接时去掉-pie
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie去掉这行
3.5.2 参考“毕业班视频第一课的start.s、init.c”修改代码,修改_TEXT_BASE的值,
把init.c放入board/samsung/smdk2440目录,修改Makefile,增加init.o
修改start.S
3.5.3 修改board_init_f,把重定位relocate_code的代码去掉
将relocate_code设置为unsigned int格式,返回id
bl r1, _TEXT_BASE
bl board_init_r/*第二阶段*/
3.5.4 修改链接脚本:把start.S,init.c,lowlevel.s等文件放到最前面
./arch/arm/cpu/u-boot.lds:
board/samsung/smdk2440/libsmdk2440.o (.text)
修改include/common.h
unsigned int board_init_f (ulong) __attribute__ ((noreturn));
【__attribute__ ((noreturn))不显示输出】
3.6 修改支持NOR Flash
修改u-boot-2012.04.01\drivers\mtd\jedec_flash.c内的jedec_table增加NOR FLASH类型
修改u-boot-2012.04.01\include\configs\smdk2440.h
#define CONFIG_SYS_MAX_FLASH_SECT (128)
在u-boot-2012.04.01\drivers\mtd\cfi_flash.c增加
#define DEBUG 1 #define _DEBUG 1
修改u-boot-2012.04.01\arch\arm\lib\board.c
//puts(failed);
//hang();
烧写执行
SMDK2440 # protect off all、测试NOR FLASH是否可以读写
SMDK2410 # flinfo
修复重定位时留下的bug,重新设置sp
第二阶段要重新设置栈设置到addr_sp2
start.S:
.globl base_sp
base_sp:
.long 0
ldr sp, base_sp
board.c的unsigned int board_init_f(ulong bootflag)函数内:
extern ulong base_sp;
base_sp = addr_sp;
//relocate_code(addr_sp, id, addr);
3.7 修改U-Boot支持NAND Flash
修改:include/configs/smdk2440:#define CONFIG_CMD_NAND
把u-boot-2012.04.01\drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c
分析过程:
board.c > nand_init()
> nand_init_chip()
> board_nand_init()[设置nand_chip结构体,提供底层操作函数]
> nand_scan()
> nand_set_defaults()
>chip->select_chip = nand_select_chip;
>chip->cmdfunc = nand_command
>nand_get_flash_type()
>chip->select_chip(mtd, 0);
>chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
nand_command//既可以用来发命令,也可以用来发列地址(页内地址)、行地址(哪一页)
chip->cmd_ctrl
s3c2440_hwcontrol
>chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
>*maf_id = chip->read_byte(mtd);
>*dev_id = chip->read_byte(mtd);
3.8 修改U-Boot支持DM9000网卡
board.c > eth_initialize(gd->bd);
>board_eth_init()
>cs8900_initialize()
通过在linux里查找dm9000用法:grep "dm9000_init" * -nR
增加下列代码:
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
测试:
*** ERROR: `ethaddr' not set
set ipaddr 10.3.10.231
set ethaddr 00:16:E6:32:6E:EC
3.9 修改U-Boot保存环境变量,易用性修改+裁剪
*** Warning - bad CRC, using default environment
u-boot-2012.04.01\include\configs\smdk2440.h
#define CONFIG_BOOTARGS "console=ttySAC0 root=/dev/mtdblock3"
#define CONFIG_BOOTCOMMAND "nand read 30000000 kernel 0x200000;bootm 30000000"
定义了bootcmd=nand read 30000000 kernel 0x200000;bootm 30000000才显示倒计时5s
#define CONFIG_BOOTDELAY 5
#define CONFIG_ETHADDR 00:16:E6:32:6E:EC
内核打印出的分区信息:
0x00000000-0x00040000:"bootloader" 256KB
0x00040000-0x00060000:"params" 128KB
0x00060000-0x00260000:"kernel" 2048KB=2M
0x00260000-0x10000000:"rootfs"
下载:
SMDK2440 # tftp 30000000 u-boot20181219.bin
SMDK2440 # protect off all
SMDK2440 # erase 0 3ffff
SMDK2440 # cp.b 30000000 0 40000
SMDK2440 # reset
SMDK2440 # set bootcmd 'nand read 30000000 kernel;bootm 30000000'
SMDK2440 # save
#define MTDIDS_DEFAULT "nand0=jz2440-0"
#define MTDPARTS_DEFAULT "mtdparts=jz2440-0:256k(u-boot)," \
"128k(params)," \
"2m(kernel)," \
"-(rootfs)"
SMDK2440 # mtdparts
SMDK2440 # help mtdparts
SMDK2440 # mtdparts default
SMDK2440 # nand erase.part kernel
SMDK2440 # tftp 30000000 uImage
SMDK2440 # nand erase.part kernel
SMDK2440 # nand write 30000000 kernel
SMDK2440 # reset
resetting ...
烧写JAFFS:
SMDK2440 # tftp 30000000 fs_mini_mdev.jffs2
SMDK2440 # nand erase.part rootfs
SMDK2440 # nand write.jffs2 30000000 0x00260000 size
set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
boot
更新U-Boot:
SMDK2440 # tftp 30000000 u-boot.bin; protect off all; erase 0 4ffff; cp.b 30000000 0 50000
烧写YAFFS:
SMDK2440 # tftp 30000000 fs_mini_mdev.yaffs2
SMDK2440 # nand erase.part rootfs
SMDK2440 # nand write.yaffs 30000000 0x00260000 889bc0(size)
ERROOR: Kernel panic - not syncing: No init found. Try passing init= option to kernel.
nand dump 260000和.yaffs2文件比较,每一页是2048,第二页是2048+64
nand dump 260800是第二页
在 u-boot-2012.04.01\drivers\mtd\nand\nand_util.c里修改
ops.mode = MTD_OOB_RAW;//用原始的OOB
if (rval)/*如果是非零才会错误,只写了一页数据*/!!!!!!!!!!!!!!!!!
vi u-boot-2012.04.01\drivers\mtd\nand\nand_util.c +518
if (!need_skip && !(flags & WITH_DROP_FFS)) {
改为
if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB)) {
制作补丁:
参照“18.13.3制作Uboot补丁文件步骤”。
18.17.2 移植Linux3.4.2内核
一.先下载Linux3.4.2内核,然后解压内核。
$tar xzf linux-3.4.2.tar.gz $cd linux-3.4.2
1.1 修改Makefile
$vi Makefile +195 /ARCH找到 ARCH?=$(SUBARCH)改为arm CROSS_COMPILE ?=arm-linux-
在linux-3.4.2/Documentation/Changes下查找适合的gcc编译器
1.2 选择默认配置:
$ find -name "*_defconfig" ./arch/arm/configs/s3c2410_defconfig ./arch/arm/configs/mini2440_defconfig $make s3c2410_defconfig //生成.config
查看系统支持什么单板
ls *2410* ls *2440* vi .config //可以看到MINI2440和SMDK2410
1.3 make uImage编译
ERROR 01: arch/arm/mm/tlb-v4wbi.S: Assembler messages: arch/arm/mm/tlb-v4wbi.S:64: Error: too many positional arguments make[1]: *** [arch/arm/mm/tlb-v4wbi.o] Error 1 make: *** [arch/arm/mm] Error 2 ANSWER 01: 更新编译器为4.4.3版本 $vi /etc/environment 将路径增加:/usr/local/arm/4.3.2/bin 然后重启Linux服务器
3.解压3.4.2内核创建SourceInsight工程
4.复制编译好的uImage文件到work/nfs_root
$cp arch/arm/boot/uImage /work/nfs_root/uImage_new #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_new ERROR 02: SMDK2440 # nfs 32000000 10.3.10.232:/work/nfs_root/uImage_new dm9000 i/o: 0x20000000, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 00:17:17:ff:00:00 could not establish link Using dm9000 device File transfer via NFS from server 10.3.10.232; our IP address is 10.3.10.231 Filename '/work/nfs_root/uImage_new'. Load address: 0x32000000 Loading: ################################################################ ##############T T *** ERROR: Cannot umount 能下载,但快要下载完时,却出现“ERROR: Cannot Umount”这样的错误。 或 #####################transmission timeout ############################################ ANSWER 02: 如出现checksum bad或者time out之类的错误,试着重启虚拟机的nfs服务。 在虚拟机里修改/etc/hosts文件。 如: $sudo vi /etc/hosts 目标板ip 根文件系统 10.3.10.231 /work/nfs_root 打开uboot程序查看默认的MACH_ID: gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;//193 如果s=getenv(“machid”);成功,则使用它;否则使用默认
移植Linux3.4.2步骤:
步骤1:
cd arch/arm/ find -name "mach*.o" /*可查看uImage 支持的单板*/ $find -name mach-types.h $vi ./include/generated/mach-types.h
在UBOOT里:
#set machid 16a //mach-smdk2440.c或#set machid 7CF /mach-mini2440.c #set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 /*设置bound*/ #save #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_new #bootm 32000000
步骤2:
#vi arch\arm\mach-s3c24xx\mach-smdk2440.c +162 s3c24xx_init_clocks(16934400);改为s3c24xx_init_clocks(12000000);
步骤3:配置/编译
$ make s3c2410_defconfig 或 make mini2440_defconfig $ make uImage
步骤4:重复步骤1
linux乱码解决后显示的错误: 0x000000000000-0x000000004000 : "Boot Agent" mtd: partition "Boot Agent" doesn't end on an erase block -- force read-only 0x000000000000-0x000000200000 : "S3C2410 flash partition 1" 0x000000400000-0x000000800000 : "S3C2410 flash partition 2" 0x000000800000-0x000000a00000 : "S3C2410 flash partition 3" 0x000000a00000-0x000000e00000 : "S3C2410 flash partition 4" 0x000000e00000-0x000001800000 : "S3C2410 flash partition 5" 0x000001800000-0x000003000000 : "S3C2410 flash partition 6" 0x000003000000-0x000010000000 : "S3C2410 flash partition 7"
二.修改分区
根据上一步的错误,可知,linux3.4.2系统的分区太多。
按照错误信息,在服务器搜索
$grep "\"Boot\ Agent\"" * -nR vi arch/arm/mach-s3c24xx/common-smdk.c +111 修改static struct mtd_partition smdk_default_nand_part[] = { $make uImage && cp arch/arm/boot/uImage /work/nfs_root/uImage_new
下载内核:
#nfs 32000000 10.3.10.232:/work/nfs_root/uImage_new #bootm 32000000 /*启动后提示文件系统错误*/
重新下载文件系统:
#nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev.yaffs2 #nand erase.part rootfs #nand write.yaffs 30000000 460000 889bc0 或者 #nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev.jffs2 #nand erase.part rootfs; nand write.jffs2 30000000 460000 $filesize #set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2 //重启后仍有错误,说明旧的文件系统不能使用,需要重新制作
三. 制作文件系统
1.解压下载的文件系统
$ tar xjf busybox-1.20.0.tar.bz2 busybox-1.20.0$ make menuconfig 错误: Your display is too small to run Menuconfig! It must be at least 19 lines by 80 columns. make[1]: *** [menuconfig] Error 1 make: *** [menuconfig] Error 2 解决方案:缩小字体或移动到大的显示屏
2.设置Busybox
Busybox Settings ---> Busybox Options ---> Cross Complier prefix(NEW) arm-linux- busybox-1.20.0$ make /work/nfs_root/$ mkdir fs_mini_mdev_new //新建文件系统文件夹 /work/nfs_root/$ cd fs_mini_mdev_new
2.1根文件系统制作
2.1.1.安装到新建的文件系统文件夹:
busybox-1.20.0$ vi README //查看使用说明
busybox-1.20.0$make install CONFIG_PREFIX=/work/nfs_root/fs_mini_mdev_new
2.1.2.复制库
$ echo $PATH $ cd /usr/local/arm/4.3.2/bin //查找库内容 /usr/local/arm/4.3.2/bin$ find -name lib ./arm-none-linux-gnueabi/libc/armv4t/lib ./arm-none-linux-gnueabi/libc/armv4t/usr/lib $mkdir /work/nfs_root/fs_mini_mdev_new/lib $ cp arm-none-linux-gnueabi/libc/armv4t/lib/*so* /work/nfs_root/fs_mini_mdev_new/lib -d $mkdir /work/nfs_root/fs_mini_mdev_new/usr/lib -p $ cp arm-none-linux-gnueabi/libc/armv4t/usr/lib/*so* /work/nfs_root/fs_mini_mdev_new/usr/lib/ -d
2.1.3.构建etc目录
/work/nfs_root$ cp fs_mini_mdev/etc fs_mini_mdev_new -rf //vi inittab 修改s3c2410_serial0为console //vi init.d/rcS //cat fstab
2.1.4.构建dev目录
/work/nfs_root/fs_mini_mdev_new$ mkdir dev $ ls -l /dev/console /dev/null查看主、次设备号 /work/nfs_root/fs_mini_mdev_new$ sudo mknod dev/console c 5 1 /work/nfs_root/fs_mini_mdev_new$ sudo mknod dev/null c 1 3
2.1.5.其他空目录
/work/nfs_root/fs_mini_mdev_new$ mkdir proc mnt tmp sys root
2.2制作JAFFS2
/work/nfs_root$ mkfs.jffs2 -n -s 2048 -e 128KiB -d fs_mini_mdev_new -o fs_mini_mdev_new.jffs2 //2048一个扇区大小,128KiB可插除扇区 烧写: #nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev_new.jffs2 #nand erase.part rootfs; nand write.jffs2 30000000 460000 $filesize #set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2 #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_new #bootm 32000000 出现错误: Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004 SIGILL illegal instruction 重新配置内核支持EABI $make menuconfig Kernel Features ---> [*]Use arm EABI... $make uImage && cp arch/arm/boot/uImage /work/nfs_root/uImage_eabi #set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2 #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_eabi #bootm 32000000
四.移植YAFFS文件系统
1.获得源码
git clone git://www.aleph1.co.uk/yaffs2
2.打补丁
$cd yaffs-dir 进入yaffs目录 $./patch-ker.sh c m linux-tree eg. $/patch-ker.sh c m /work/system/linux-3.4.2
3.配置内核支持YAFFS
linux-3.4.2$ make menuconfig -> File systems -> Miscellaneous filesystems (MISC_FILESYSTEMS [=y]) ->[*] yaffs2 file system support (YAFFS_FS [=n])
4.编译、使用uImage
linux-3.4.2$ make uImage Error: d_make_root(inode) //Linux-3.4.2内核的mtd结构体的名字都加了下划线
修改完错误后,编译:
$ make uImage && cp arch/arm/boot/uImage /work/nfs_root/uImage_yaffs
5.制作、烧写yaffs映象
/work/nfs_root$ mkyaffs2image fs_mini_mdev_new fs_mini_mdev_new.yaffs2 mkyaffs2image命令哪来的? yaffs_source_util_larger_small_page_nand.tar.bz2/Development_util_ok/yaffs2/utils --->执行make 或git clone git://www.aleph1.co.uk/yaffs2/utils --->执行make 这里面的程序有问题,修改 #nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev_new.yaffs2 #nand erase.part rootfs; nand write.yaffs 30000000 460000 $filesize
6.启动
#set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_yaffs; bootm 32000000
7.若没成功,用替代法查找问题
7.1 UBOOT可能有问题:换上1.1.6的UBOOT
#tftp 30000000 u-boot.bin #nand erase.part u-boot #nand write 30000000 u-boot #reset #nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev_new.yaffs2 #nand erase rootfs #nand write.yaffs 30000000 460000 $(filesize) #set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 #nfs 32000000 10.3.10.232:/work/nfs_root/uImage_yaffs #bootm 32000000
发现1.1.6的UBOOT没问题,所以就是我们移植的新UBOOT有BUG:
drivers\mtd\nand\Nand_util.c if (!need_skip && !(flags & WITH_DROP_FFS)) { 改为 if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB)) {
五.裁剪内核
System Type ---> SAMSUNG S3C24XX SoCs Support ---> 进入选择不需要的即可 -> File systems //进入选择熟悉的修改即可 根据输出裁剪内核 mousedev: PS/2 mouse device common for all mice 本次修改制作了u-boot_new.bin, uImage_small, fs_mini_mdev_new.yaffs
重烧整个系统:
使用jtag工具烧u-boot_new.bin
或使用uboot来更新自己: tftp 30000000 u-boot_new.bin; nand erase.part u-boot; nand write 30000000 u-boot
启动uboot,用它来烧写内核、FS
nfs 30000000 10.3.10.232:/work/nfs_root/uImage_small; nand erase.part kernel; nand write 30000000 kernel nfs 30000000 10.3.10.232:/work/nfs_root/fs_mini_mdev_new.yaffs2; nand erase.part rootfs; nand write.yaffs 30000000 460000 $filesize 设置参数 set 'nand read 30000000 kernel;bootm 30000000' set bootargs console=ttySAC0,115200 root=/dev/mtdblock3 set machid 16a save
制作Linux3.4.2内核补丁:参照“18.13.3制作Uboot补丁文件步骤”。
-------------------------------------------
文中所用软件在试用期内。若涉及商业用途或想有更好的用户体验,建议购买正版!
如果觉得这篇文章对您有小小帮助的话,记得在右下角点个“推荐”哦,博主在此万分感谢!
打赏请您扫下面二维码!谢谢!