Chinaunix首页 | 论坛 | 博客
  • 博客访问: 306349
  • 博文数量: 63
  • 博客积分: 1482
  • 博客等级: 上尉
  • 技术积分: 1185
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-12 19:06
个人简介

hello world!

文章分类

全部博文(63)

分类: LINUX

2011-04-05 21:57:42

Boot Loader 的 stage2 通常包括以下步骤(以执行的先后顺序):

  • 初始化本阶段要使用到的硬件设备。
  • 检测系统内存映射(memory map)。
  • 将 kernel 映像和根文件系统映像从 flash 上读到 RAM 空间中。
  • 为内核设置启动参数。
  • 调用内核。

      根据此通用步骤来编写我们的BootLoader引导程序。

1、初始化本阶段需要用到硬件设备,在E-boot中需要用到串口,同时根据硬件初始化GPIO设置。

  1.     uart0_init(); //串口初始化

  2.     printf("\n\rGPIO initialize ...\n\r");//然后即可使用以前编写的printf()函数来进行串口调试
  3.     
  4.     Port_Init();  //通用GPIO接口设置

 

  1. void Port_Init(void)
  2. {
  3.     GPACON = 0x7fffff;
  4.     GPBCON = 0x044555;
  5.     GPBUP = 0x7ff;        // The pull up function is disabled GPB[10:0]

  6.     GPCCON = 0xaaaaaaaa;
  7.     GPCUP = 0xffff;    // The pull up function is disabled GPC[15:0]

  8.     GPDCON = 0x00151544;
  9.     GPDDAT = 0x0430;
  10.     GPDUP = 0x877A;
  11.     GPECON = 0xaa2aaaaa;
  12.     GPEUP = 0xf7ff;    // GPE11 is NC

  13.     GPFCON = 0x55aa;
  14.     GPFUP = 0xff;        // The pull up function is disabled GPF[7:0]

  15.     GPGCON = 1<<8;
  16.     GPGDAT = 0;
  17.     GPHCON = 0x16faaa;
  18.     GPHUP = 0x7ff;        // The pull up function is disabled GPH[10:0]

  19.     EXTINT0 = 0x22222222;    // EINT[7:0]

  20.     EXTINT1 = 0x22222222;    // EINT[15:8]

  21.     EXTINT2 = 0x22222222;    // EINT[23:16]

  22. }

 

2、MMU设置,据网上所说,MMU和Dcache必须关闭, Dcache 随意,在以下关闭了MMU,

但是Dcahe打开也能成功引导Linux系统。

  1.     MMU_EnableICache();
  2.     MMU_EnableDCache();
  1. static inline void MMU_EnableICache(void)
  2. {

  3.     asm (
  4.         "mrc p15,0,r0,c1,c0,0\n"
  5.         "orr r0,r0,#(1<<12)\n"
  6.         "mcr p15,0,r0,c1,c0,0\n"
  7.     );
  8. }

  9. static inline void MMU_EnableDCache(void)
  10. {
  11.     asm (
  12.         "mrc p15,0,r0,c1,c0,0\n"
  13.         "orr r0,r0,#(1<<2)\n"
  14.         "mcr p15,0,r0,c1,c0,0\n"
  15.     );
  16. }

3、设置Linux系统内核启动参数,此处主要需参考Linux内核中的arch/arm/include/asm/setup.h和

arch/arm/kernel/setup.c这两个文件来设置。其中用到的结构体在setup.h中均有定义。此处只设置

其最基本的参数。page_size和nr_page。参数保存在0x30000100这个位置。

  1. printf("\n\rset parameters ...\n\r");

  2.     SetParameters();
  1. static inline void SetParameters(void)
  2. {    
  3.     struct param_struct *p = (struct param_struct *)0x30000100;
  4.     memset(p, 0, sizeof(*p));
  5.     memcpy(p->commandline, LINUX_CMD_LINE, sizeof(LINUX_CMD_LINE));
  6.     p->u1.s.page_size = 4 * 1024;//MMU中用段式页表,一级页表中有4096个描述符表示4G空间
  7.     p->u1.s.nr_pages = 64 * 1024 * 1024 / (4 * 1024);//共64M内存
  8.     
  9. }

4、从Nand Flash的内核存放区拷贝Linux镜像到SDRAM中。

  1. LoadImageFromNand();
  2.   printf("\n\rload Linux image...\n\r");
  1. LoadImageFromNand()
  2. {
  3.     NandInit();   //Nand Flash 初始化
  4.     unsigned int Length;
  5.     U8 *RAM;
  6.     unsigned BlockNum;
  7.     unsigned pos;

  8.     Length = 0x500000; //Nand Flash 中内核存放区的总大小

  9.     Length = (Length + BLOCK_SIZE - 1) >> (BYTE_SECTOR_SHIFT + SECTOR_BLOCK_SHIFT) << (BYTE_SECTOR_SHIFT + SECTOR_BLOCK_SHIFT); // align to Block Size

  10.       
  11.         /** Nand Flash 中内核存放区的开始位置0X60000 **/
  12.     BlockNum = 0x60000 >> (BYTE_SECTOR_SHIFT + SECTOR_BLOCK_SHIFT);
  13.     RAM = (U8 *) 0x30008000; //拷贝到内存中的位置

  14.     for (pos = 0; pos < Length; pos += BLOCK_SIZE) {
  15.         unsigned int i;
  16.         // skip badblock

  17.         for (;;) {
  18.             if (NandIsGoodBlock
  19.              (BlockNum <<
  20.              (BYTE_SECTOR_SHIFT + SECTOR_BLOCK_SHIFT))) {
  21.                 break;
  22.             }
  23.             BlockNum++;    //try next

  24.         }
  25.         for (i = 0; i < BLOCK_SIZE; i += SECTOR_SIZE) {
  26.             int ret =
  27.              NandReadOneSector(RAM,
  28.                      (BlockNum <<
  29.                      (BYTE_SECTOR_SHIFT +
  30.                         SECTOR_BLOCK_SHIFT)) + i);
  31.             RAM += SECTOR_SIZE;
  32.             ret = 0;

  33.         }

  34.         BlockNum++;
  35.     }    
  36. }

5、跳转到内核运行。r0必须设为0,r1为机器ID码,r2为内核引导参数存放地址

  1. theKernel(0,1999,0x30008000);
  1. //内核跳转程序

  2. void (*theKernel)(int zero, int arch, U32 params_addr) = (void (*)(int, int, U32))0x30008000;

        实验发现,第三个参数传递进去的TAG首地址似乎没有起到作用,因为启动时总是找不到正确的启动参数。后来发现内核有个默认的TAG首地址0x30000100,它总是到0x30000100去寻找启动参数,而不理会我们传进来的第三个参数。所以在 SetParameters()中我们将参数放在0x30000100处。

6、运行结果可以看到“,Uncompressing Linux........................................ done, booting the kernel.”即可。

 

以下为能直接运行的二进制文件,下载到Nand Flash Black0 直接以Nand Flash运行。
阅读(1520) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~