/******************************************************************/
 PC         由bios       引导操作系统windows 识别C D盘        操作应用程序
 嵌入式系统 由bootloader 引导Linux内核        挂接根文件系统     运行应用程序bootloader最终目的:启动内核
bootloader有很多种 用的比较多的是 u-boot
u-boot功能:
     从flash中读出内核
     初始化SDRAM
     初始化时钟
     初始化看门狗
     初始化串口
     为了开发方便:写flash 网卡 usb功能
     启动内核
     
 u-boot:复杂一点的单片机程序u-boot
         输入help可以打印u-boot的所有命令
         输入? + 命令 打印命令用法
         输入menu进入菜单
         输入print 打印出来环境变量
         输入 set  设置环境变量
         输入 save 保存
         输入 grep " "  搜素内容
         不同命令之间可以用;隔开
         
 readme:关于u-boot的说明操作过程:
     解压缩    打补丁 patch文件:
     打补丁说明 忽略---补丁文件说明的第一个参数 -p1
     -表示原来的代码
     +修改后的代码    patch命令:
         patch -p1 < ../u-boot-1.16_jz2440.patch    配置 make 100ask24x0_config
    编译 make
     
 分析配置过程:
     #makeconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
     #     $1            $2             $3            $4        $5        $6    makeconfig:
         $#         表示参数的个数
         $( )     定义什么
         echo     打印 执行什么
         :        依赖于谁
         >        表示新建一个文件
         >>        表示追加一个文件
         
         ln -s asm-arm asm                 建立一个asm链接文件指向asm-arm
         ln -s arch-s3c24x0 asm-arm/arch 建立一个asm-arm/arch链接文件指向arch-s3c24x0
         ln -s proc-armv asm-arm/proc      建立一个asm-arm/proc链接文件指向proc-armv分析编译过程:
     OBJS = cpu/arm920t/start.o
     ...
     
     LIBS += board/100ask24x0/lib100ask24x0.a
     ...
     
     make命令的最后面就是一个连接命令Makefile分析 结论:
     运行的第一个文件是 cpu/arm920t/start.S
     连接地址:board/1  00ask24x0/u-boot.lds    +    0x33F80000
     
     start.S:
     u-boot-1:
         set svc32
         关看门狗
         屏蔽中断
         sdram初始化
         设置栈
         时钟
         重定位 flash => sdram
         清bss段 初始化为0的变量
         
     u-boot-2:
         调用c函数 strat_armboot
         
         flash_init();
         nand_init();
         
         环境变量:
             默认的
             flash上保存的
             
         主循环mainloop();
         
         启动内核:
             s = getenv("bootcmd");
             run_command(s);
         u-boot界面:
             readline();
             run_command();
         
 u-boot的命令实现:
     命令结构体:
         struct cmd_tbl_s{
             name;
             maxargs;
             repeatable;
             (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
             char *uasge;
             #ifdef CFG_LONGHELP
                 char *help;
             #endif
             
             #ifdef CONFIG_AUTO_COMPLETE
                 int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
             #endif
         };
     find_cmd();
     
 启动内核:
     nand read.jffs2 0x30007FC0 kernel;
         从内核中读出内核 从哪里读(kernel 分区) 放到哪里去(0x30007FC0)?
     linux下的flash没有分区
         bootloader env kernel root 在源码配置文件里面写死的
         kernel 分区:
             起始地址:0x00060000 长度:0x00200000
         
     flash上面存的内核为Uimage 包含头部和真正的内核
     头部里面有加载地址和入口地址
     
     根据头部移动到合适的地方
     启动:do_boot_linux();
         uboot告诉内核一些参数
             在某个地址按照某种格式保存数据 格式称为TAG
                 start_tag
                 memory_tag
                 commandline_tag
                 end_tag
         跳到入口地址 启动内核 thekernel();
         
     
     
     
 /******************************************************************/    
 从零开始写一个bootloader:最简单的bootloader编写步骤:
     1,初始化硬件:关看门狗 设置时钟 设置SDRAM 初始化NAND FLASH
     2, 把内核从NAND FLASH读到SDRAM
         如果bootloader比较大 要重定位 把bootloader本身的代码从flash复制到链接地址
     3,设置要传给内核的参数 tag
     4,跳到入口地址处执行
     
     汇编指令:
         ldr:
             伪指令 如果操作数比较长的时候
         mov:
             伪指令 传递参数
         str:
             存储参数
         adr:
             伪指令
         add:
             增加
         cmp:
             比较
         bne:
             跳转
         bl:
             相对跳转
         sub:
             执行减法    内核启动时 要设置串口
     
     把bootloader的代码拷贝到SDRAM里面执行:
         判断是从nor flash启动还是从nand flash 启动
         nor flash的特点是0地址不能写 不能像内 存一样写
         nand flash 的0地址可以写
     
     设置参数
     
 改进:
     提高CPU主频
     使用ICATCH 指令CATCH   DCATCH使用的前提是开MMU    
     
     
     
 /******************************************************************/
 移植一个最新的U-boot 分析启动过程:
     安装最新u-boot
     
     编译
     
     pie 链接的时候加上pie会生成位置无关码 不管位置在哪都能正确执行
     
     ......
     
     重定位代码:
         nor flash复制到sdram里面之后 全局变量用新的地址访问
         以前的程序是链接地址是0,访问全局变量,调用函数时是使"基于0地址编译得到的地址"
         现在把程序复制到了SDRAM 需要修改代码 把"基于0地址编译得到的地址"改为新地址
         程序里面的有些地址在链接时不能确定 要到运行时才能确定:fixabs
         
     ......     创建单板:
         cd board/samung/
         cp smdk2410 smdk2410 -rf
         cd ../../include/configs/
         cp smdk2410.h smdk2440.h
         修改boards.cfg:
         仿照
             smdk2410     arm        arm920t     -    samung        s3c24x0
         添加
             smdk2440    arm        arm920t        -    samung        s3c24x0
         
         烧写看结果:无任何反应
         
         
 修改u-boot支持时钟和SDRAM
     发现不足:    U-boot里面先以60MHZ的时钟计算参数来设置内存控制器但是MPLL还没有进行设置
     处理措施:    把MPLL的设置放到start.S里面 取消board_early_init_f里对MPLL的设置
                 编译出来的u-boot非常大 可以先烧写主光盘里面的u-boot来烧写新的u-boot
                 usb 1 30000000     //下载新的u-boot
                 protect off all
                 erase 0 7ffff
                 cp.b 30000000 0 80000
                 
     乱码问题:    查看串口波特率设置 发现设置波特率函数里面没有定义CONFIG_S3C2440
                 #define CONFIG_S3C2440
                 看Makefile //NAND_CONFIG 串口正常输出
                 
 修改u-boot支持NAND启动:
     上电的时候用NAND读函数把代码移动到SDRAM里面去
     
     原来的代码在链接时加了"-pie"选项,使得u-boot里面多了"*(.rel*)", "*(.dynsym)"
     使得程序非常的大,不利于程序从NAND FLASH上面启动(重定位之前的代码应该少于4K)
     去掉 "pie"选项
     参考毕业班第一课来修改代码,支持NAND FLASH
     把init.c放入到board/Samsung/smdk2440目录 修改Makefile
     修改CONFIG_SYS_TEXT_BASE为0x33f80000
     修改start.S
     修改board_init_f,把relocate_code去掉
     修改链接脚本    把start.S init.s lowlevel.s 等文件放在前面
     修改Makefile
     
 修改u-boot支持NOR FLASH启动:
     NOR FLASH就和内存一样 好多函数已经写好了
     修改drivers/mtd/jedec_flash.c 加上新的型号
     #define CONFIG_SYS_MAX_FLASH_SECT(128)
     
     修改重定位时留下的BUG
     
 修改u-boot支持DM9000启动:
     设置内存控制器 时序
     确定访问地址
     
     eth_initialize
         board_eth_init
             cs8900_initialize
     *** ERROR: 'ethaddr' not set
     
     set ipaddr 192.168.1.17
     set ethaddr 00:0c:29:4d:e4:f4
     
     至此可以ping通开发板
     启动windows上面的tftp工具
     
     set serverip 192.16.1.3
     
     tftp 30000000 uImage
     
 修改u-boot支持NAND FLASH:
     修改: include/configs/smdk2440.h  #define CONFIG_CMD_NAND
     把drivers/mtd/nand/s3c2410_nand.c  复制为    s3c2440_nand.c
     
     分析过程:
         nand_init
             nand_init_chip
                 board_nand_init
                     设置nand_chip结构体,提供底层的操作函数
                 nand_scan
                     nand_scan_ident
                         nand_set_defaults
                             chip->select_chip = nand_select_chip;
                             chip->cmdfunc = nand_command;
                             chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
                         nand_get_flash_type
                             chip->select_chip
                             chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
                                 nand_command() //既可以用来发命令 也可以用来发地址
                                     chip->cmd_ctrl
                                         s3c2440_hwcontrol
                                         
                             chip->cmdfunc(mtd, NAND_CMD_READTD, 0x00, -1);
                             *maf_id = chip->read_byte(mtd);
                             *dev_id = chip->read_byte(mtd);
                             
 修改u-boot支持烧写yaffs映像 及 制作补丁:
     烧写jffs2:
         tftp 30000000 fs_mini_mdev.jffs2
         nand erase.part rootfs
         nand write.jffs2 30000000 0x00260000 5b89a8
         
         set bootargs console=ttysacd root=/dev/mtdblock3 rootfstye=jffs2
         
     烧写YAFFS:
         tftp 30000000 fs_mini_mdev.jffs2
         nand erase.part rootfs
         nand write.yaffs 30000000 260000
         
     更新u-boot:
         tftp 30000000 u-boot_new.bin; protect off all; erase 0 3ffff; cp.b 30000000 0 40000
         
     制作补丁文件并且打补丁:
         make disclean
         ls
         rm u-boot.lds
         rm ^c
         mv u-boot-2012.04.01 u-boot-2012.04.01_100ask
         tar xjf u-boot-2012.04.01.tar.bz2
         difff -urN u-boot-2012.04.01 u-boot-2012.04.01_100ask > u-boot-2012.04.01_100ask.patch
         
         cd u-boot-2012.04.01/
         patch -p1 << ../u-boot-2012.04.01_100ask.patch
         make smdk2440_config
         make
         生成 u-boot.bin
         
 u-boot之裁剪和修改默认参数:
     环境参数存在flash上面 要设置一下
     去掉不需要的东西