网站导航: 首页 > 设计参考 > 正文 文章搜索
S3C2410 bootloader(vivi)阅读笔记
 
文章编号:
081228172309
文章分类: 单片机 ARM
点 击:
...
关 键 词: S3C2410,bootloader,vivi,阅读笔记
文章来源:
网络
摘 要:
Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,redboot,lilo等等。Vivi 是韩国mizi公司专门为三星s3c2410芯片设计的Bootloader...

       建议读一读《嵌入式系统Boot Loader技术内幕》(詹荣开著)。什么是Bootloader就不再这里废话了,看看上面的文章就明了了。
      Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,redboot,lilo等等。Vivi 是韩国mizi公司专门为三星s3c2410芯片设计的Bootloader。
先来看看vivi的源码树:
vivi-+-arch-+-s3c2410
|-Documentation
|-drivers-+-serial
|           ‘  -mtd-+-maps
|                  |-nor
|                  ‘-nand
|-include-+-platform
|           |-mtd
|           ‘-proc
|-init
|-lib-+-priv_data
|-scripts-+-lxdialog
|-test
|-util
可以google一下,搜到源码vivi.tar.gz。
前面提到的文件已经系统的分析了bootloader的,这里就按源代码来具体说事。vivi也可以分为2个阶段,阶段1的代码在arch/s3c2410/head.S中,阶段2的代码从init/main.c的main函数开始。

阶段1
阶段1从程序arch/s3c2410/head.S开始,按照head.S的代码执行顺序,一次完成了下面几个任务:

  1. 关WATCH DOG (disable watch dog timer)
    上电后,WATCH DOG默认是开着的
  2. 禁止所有中断 (disable all interrupts)
    vivi中不会用到中断,中断是系统的事,bootloader可不能去干这事的(不过这段代码实在多余,上电后中断默认是关闭的)
  3. 初始化系统时钟(initialise system clocks)
    启动MPLL,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为“Asynchronous bus mode”。
  4. 初始化内存控制寄存器(memsetup)
    S3c2410共有15个寄存器,在此开始初始化13个寄存器。
  5. 检查是否从掉电模式唤醒(Check if this is a wake-up from sleep)若是,则调用WakeupStart函数进行处理。
  6. 点亮所有LED (All LED on)
    点一下灯,通知外面的同志,告诉他们有情况发生。
  7. 初始化UART0 (set GPIO for UART & InitUART)
    a.设置GPIO,选择UART0使用的引脚
    b.初始化UART0,设置工作方式(使用FIFO)、波特率115200 8N1、无流控等。这可是使用串口与s3c2410通信的条件啊,在终端也要如此设置。
  8. 跳到内存测试函数(simple memory test to find some DRAM flaults)
    当然要定义了CONFIG_BOOTUP_MEMTEST这个参数才会跳到内存测试。
  9. 如果定义了以Nand flash方式启动(#ifdef CONFIG_S3C2410_NAND_BOOT),则此时要将vivi所有代码(包括阶段1和阶段2)从Nand flash复制到SDRAM中(因为在Nand flash中是不能执行程序的,它只能做为程序和数据的存储器,而Nor flash可就不同了,Nor flash可以执行程序,但贵是它发展的瓶颈):
    a.设置nand flash控制寄存器
    b.设置堆栈指针
    c.设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单位)
    d.调用nand_read_ll进行复制
  10. 跳到bootloader的阶段2运行,亦即调用init/main.c中的main函数(get read to call C functions)
    a.重新设置堆栈
    b.设置main函数的参数
    c.调用main函数

head.S有900多行,都是些arm汇编,看的云山雾罩,汇编看来是忘的差不多了,所以这部分代码也看的相当糙,只知道大概在干什么,至于个中缘由就不是很了解。先学学arm汇编再回来看。

阶段2
从init/main.c中的main函数开始,终于步入C语言的世界了。Main函数总共有8步(8 steps),先看看源代码:

 
  1. int main(int argc, char *argv[])   
  2. {   
  3.         int ret;   
  4.           
  5.         /*  
  6.         * Step 1:  
  7.         */  
  8.         putstr("\r\n");   
  9.         putstr(vivi_banner);    //vivi_banner是vivi执行开始的显示信息,vivi_banner在文件version.c中定义   
  10.         reset_handler();   
  11.   
  12.         /*  
  13.          * Step 2:  
  14.          */  
  15.         ret = board_init();   
  16.         if (ret) {   
  17.                 putstr("Failed a board_init() procedure\r\n");   
  18.                 error();   
  19.         }   
  20.   
  21.         /*  
  22.          * Step 3:  
  23.          */  
  24.         mem_map_init();   
  25.         mmu_init();   
  26.         putstr("Succeed memory mapping.\r\n");   
  27.   
  28.         /*  
  29.          * Now, vivi is running on the ram. MMU is enabled.  
  30.          * Step 4:  
  31.      */  
  32.         /* initialize the heap area*/  
  33.         ret = heap_init();   
  34.         if (ret) {   
  35.                 putstr("Failed initailizing heap region\r\n");   
  36.                 error();   
  37.         }   
  38.   
  39.         /* Step 5:  
  40.          * MTD  
  41.          */  
  42.         ret = mtd_dev_init();   
  43.   
  44.         /* Step 6:  
  45.          */  
  46.         init_priv_data();   
  47.   
  48.         /* Step 7:  
  49.         */  
  50.         misc();   
  51.         init_builtin_cmds();   
  52.   
  53.         /* Step 8:  
  54.          */  
  55.         boot_or_vivi();   
  56.         return 0;   
  57. }   
  58.   

 

下面按照上面的步骤逐步来分析一下。
1、Step 1:reset_handler()
reset_handler用于将内存清零,代码在lib/reset_handle.c中。

 
  1. void  
  2. reset_handler(void)   
  3. {   
  4.     int pressed;   
  5.     pressed = is_pressed_pw_btn();  /*判断是硬件复位还是软件复位*/  
  6.      if (pressed == PWBT_PRESS_LEVEL) {   
  7.          DPRINTK("HARD RESET\r\n");   
  8.          hard_reset_handle();        /*调用clear_mem对SDRAM清0*/  
  9.      } else {   
  10.          DPRINTK("SOFT RESET\r\n");   
  11.          soft_reset_handle();        /*此函数为空*/  
  12.      }   
  13. }  


    在上电后,reset_handler调用第8行的hard_reset_handle(),此函数在lib/reset_handle.c中:
[main(int argc, char *argv[]) -> reset_handler() -> hard_reset_handle()]

 
  1. static void  
  2. hard_reset_handle(void)   
  3. {   
  4. #if 0   
  5.     clear_mem((unsigned long)(DRAM_BASE + VIVI_RAM_ABS_POS), \   
  6.     (unsigned long)(DRAM_SIZE - VIVI_RAM_ABS_POS));   
  7. #endif   
  8. /*lib/memory.c,将起始地址为USER_RAM_BASE,长度为USER_RAM_SIZE的内存清0*/  
  9.  clear_mem((unsigned long)USER_RAM_BASE, (unsigned long) USER_RAM_SIZE);   
  10. }  


先写到这儿吧。

2、Step 2:board_init()   
board_init调用2个函数用于初始化定时器和设置各GPIO引脚功能,代码在arch/s3c2410/smdk.c中:
[main(int argc, char *argv[]) > board_init()]

 
  1. int board_init(void)   
  2. {   
  3.     init_time();  /*arch/s3c2410/proc.c*/  
  4.     set_gpios();  /*arch/s3c2410/smdk.c */  
  5.     return 0;   
  6. }   

 

init_time() 这个函数对寄存器进行了简单的操作:

 
  1. void init_time(void)   
  2. {   
  3.         TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));   
  4.         /*s3c2410 data sheet P298*/  
  5.         /*TCFG0 = 0 | 0xf00 | 0 */  
  6. }  


寄存器TCFG0由三部分组成,prescaler0,prescaler1,deadzone和reserve四部分,前三部分分别对应 TCFG0_PRE0、TCFG0_PRE1、TCFG0_DZONE,TCFG0_PRE0(0)实际值为0x00,TCFG0_PRE1(15)实际值为0x0f00,而TCFG0_DZONE(0)实际值为 0x000000。实际中,vivi并未使用定时器,这个函数就可以忽略。set_gpios()用于选择GPA至GPH端口各引脚的功能及是否使用各引脚的内部上拉电阻,并设置外部中断源寄存器EXTINT0-2(vivi中未使用外部中断)。

 
  1. void set_gpios(void)   
  2. {   
  3.               GPACON  = vGPACON;   
  4.               GPBCON  = vGPBCON;   
  5.               GPBUP   = vGPBUP;   
  6.               GPCCON  = vGPCCON;   
  7.               GPCUP   = vGPCUP;   
  8.               GPDCON  = vGPDCON;   
  9.               GPDUP   = vGPDUP;   
  10.               GPECON  = vGPECON;   
  11.               GPEUP   = vGPEUP;   
  12.               GPFCON  = vGPFCON;   
  13.               GPFUP   = vGPFUP;   
  14.               GPGCON  = vGPGCON;   
  15.               GPGUP   = vGPGUP;   
  16.               GPHCON  = vGPHCON;   
  17.               GPHUP   = vGPHUP;   
  18.               EXTINT0 = vEXTINT0;   
  19.               EXTINT1 = vEXTINT1;   
  20.               EXTINT2 = vEXTINT2;   
  21. }   

 

        以第三行为例,vGPACON的值为0x007fffff,查找s3c2410用户手册可知,该参数将GPACON的23位全部置1。各位功能需察看s3c2410用户手册

3、Step 3:建立页表和启动MMU
          mem_map_init();
          mmu_init();

mem_map_init函数用于建立页表,vivi使用段式页表,只需要一级页表。它调用3个函数,代码在arch/s3c2410/mmu.c中:

 
  1. [main(int argc, char *argv[]) > mem_map_init(void)]   
  2. void mem_map_init(void)   
  3. {   
  4.     #ifdef CONFIG_S3C2410_NAND_BOOT           
  5. /*CONFIG_S3C2410_NAND_BOOT = y ,在文件include/autoconf.h中定义*/  
  6.     mem_map_nand_boot();         
  7. /* 最终调用mem_mepping_linear, 建立页表 */  
  8.     #else   
  9.         mem_map_nor();   
  10.     #endif   
  11.     cache_clean_invalidate();/* 清空cache,使无效cache */    
  12.     tlb_invalidate();        /* 使无效快表TLB */  
  13. }  


第9、 10行的两个函数可以不用管它,他们做的事情在下面的mmu_init函数里又重复了一遍。对于本开发板,在.config中定义了 CONFIG_S3C2410_NAND_BOOT。mem_map_nand_boot()函数调用mem_mapping_linear()函数来最终完成建立页表的工作。页表存放在SDRAM物理地址0x33dfc000开始处,共16K:一个页表项4字节,共有4096个页表项;每个页表项对应 1M地址空间,共4G。mem_map_init先将4G虚拟地址映射到相同的物理地址上,NCNB(不使用cache,不使用write buffer)——这样,对寄存器的操作跟未启动MMU时是一样的;再将SDRAM对应的64M空间的页表项修改为使用cache。 mem_mapping_linear函数的代码在arch/s3c2410/mmu.c中:

 
  1. [main(int argc, char *argv[]) > mem_map_init(void) > mem_map_nand_boot( ) > mem_mapping_linear(void)]   
  2. static inline void mem_mapping_linear(void)   
  3. {    
  4.     unsigned long pageoffset, sectionNumber;   
  5.     putstr_hex("MMU table base address = 0x", (unsigned long)   
  6. mmu_tlb_base);   
  7.     /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, not bufferable */  
  8.     /* mmu_tlb_base = 0x33dfc000*/  
  9.     for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {   
  10.         pageoffset = (sectionNumber << 20);   
  11.         *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset |   
  12.         MMU_SECDESC;   
  13.     }   
  14.                 
  15.  /* make dram cacheable */  
  16.  /* SDRAM物理地址0x3000000-0x33ffffff,  
  17.  DRAM_BASE=0x30000000,DRAM_SIZE=64M*/  
  18.     for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE); \   
  19.         pageoffset += SZ_1M) {   
  20.         //DPRINTK(3, "Make DRAM section cacheable: 0x%08lx\n",             pageoffset);   
  21.         *(mmu_tlb_base + (pageoffset >> 20)) = \   
  22.         pageoffset | MMU_SECDESC | MMU_CACHEABLE;   
  23.     }   
  24. }   

 

 
相关文章:
s3c2410 Timer工作原理[图]
虚拟SPI时序在TC77与S3C2410通信中的应用[图]
s3c2410 MMU(存储器管理单元)讲解[图]
s3c2410 CACHES,WRITE BUFFER讲解[图]
S3C2410中的脉宽调制定时器(PWM)
S3C2410 中断程序的实现
s3c2410 watchdog详解
s3c2410 中断异常处理[图]
基于ARM9芯片S3C2410a的GPRS数据终端设计
ARM系统中DMA方式在数据采集中的应用[图]
AD7888与S3C2410的SPI接口及Linux下嵌入式驱动的实现[图]
基于s3c2410的ARMer9开发平台的使用
ARM S3C2410硬件手册重点
基于ARM S3C2410与TMS320C6416的接口设计[图]
S3C2410上Jffs2的移植
ARM S3C2410驱动TFT-LCD的研究[图]
MINIGUI在S3C2410开发板的移植
mplayer在S3C2410上的移植
在S3C2410上移植yaffs2文件系统
s3c2410 LCD图片显示
S3C2410 LCD 驱动程序移植及GUI程序编写[图]
S3C2410X开发总结及心得
U-Boot在S3C2410开发板上的移植
基于ARM的嵌入式系统Bootloader启动流程分析
S3C2410初始化
S3C2410通过IIS总线与音频芯片UDA1380进行通信
在S3C2410上移植bluetooth(蓝牙)
S3c2410软件调试总结
S3C2410上触摸屏的应用实例
S3c2410的触摸屏及模数转换
S3C2410的快速启动技术
关于三星S3C44B0X目标板的uClinux Bootloader
基于嵌入式linux和s3c2410平台的视频采集
S3c2410 LCD驱动学习心得
s3c2410移植MPlayer到linux2.6

12 下一页
 
最新开源项目
 
 
  查看更多...  
 
本站相关产品   淘宝网店
 




 
  查看更多...  

 

本站程序由百合电子工作室开发和维护
Copyright @ baihe electric studio
渝ICP备09006681号-4