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

mmu_init()函数用于启动MMU,它直接调用arm920_setup()函数。arm920_setup()的代码在arch/s3c2410/mmu.c中:

 
  1. [main(int argc, char *argv[]) > mmu_init( ) > arm920_setup( )]   
  2. static inline void arm920_setup(void)   
  3. {   
  4.     unsigned long ttb = MMU_TABLE_BASE;   
  5.     /* MMU_TABLE_BASE = 0x33dfc000 */  
  6.     __asm__(   
  7.         /* Invalidate caches */  
  8.         "mov    r0, #0\n"  
  9.         "mcr    p15, 0, r0, c7, c7, 0\n"    /* invalidate I,D caches on v4 */  
  10.         "mcr    p15, 0, r0, c7, c10, 4\n"   /* drain write buffer on v4 */  
  11.         "mcr    p15, 0, r0, c8, c7, 0\n"    /* invalidate I,D TLBs on v4 */  
  12.         10      /* Load page table pointer */  
  13.         "mov    r4, %0\n"  
  14.         "mcr    p15, 0, r4, c2, c0, 0\n"    /* load page table pointer */  
  15.         /* Write domain id (cp15_r3) */  
  16.         14      "mvn    r0, #0\n"    /* Domains 0b01 = client, 0b11=Manager*/  
  17.         15      "mcr    p15, 0, r0, c3, c0, 0\n"  
  18.         /* load domain access register,write domain 15:0, 用户手册P548(access permissions)*/  
  19.         /* Set control register v4 */  
  20.         "mrc    p15, 0, r0, c1, c0, 0\n"    /* get control register v4 */  
  21.         /*数据手册P545:read control register */  
  22.         /* Clear out 'unwanted' bits (then put them in if we need them) */  
  23.         /* ..VI ..RS B... .CAM */   /*这些位的含义在数据手册P546*/  
  24.         "bic r0, r0, #0x3000\n"  /* ..11 .... .... .... */  
  25.         /*I(bit[12])=0 = Instruction cache disabled*/  
  26.         /*V[bit[13]](Base location of exception registers)=0 = Low addresses = 0x0000 0000*/  
  27.         "bic r0, r0, #0x0300\n"      /* .... ..11 .... .... */  
  28.            
  29.         /*R(ROM protection bit[9])=0*/  
  30.         /*S(System protection bit[8])=0*/  
  31.         /*由于TTB中AP=0b11(line141),所以RS位不使用(P579)*/  
  32.         "bic r0, r0, #0x0087\n"      /* 0x0000000010000111 */  
  33.         /*M(bit[0])=0 = MMU disabled*/  
  34.         /*A(bit[1])=0 =Data address alignment fault checking disable*/  
  35.         /*C(bit[2])=0 = Data cache disabled*/  
  36.         /*B(bit[7])=0= Little-endian operation*/  
  37.         /* Turn on what we want */  
  38.         /* Fault checking enabled */  
  39.         "orr r0, r0, #0x0002\n"      /* .... .... .... ..10 */  
  40.         /*A(bit[1])=1 = Data address alignment fault checking enable*/  
  41.     #ifdef CONFIG_CPU_D_CACHE_ON     /*is not set*/   
  42.         "orr    r0, r0, #0x0004\n"      /* .... .... .... .100 */  
  43.         /*C(bit[2])=1 = Data cache enabled*/  
  44.     #endif    
  45.     #ifdef CONFIG_CPU_I_CACHE_ON     /*is not set*/   
  46.         "orr    r0, r0, #0x1000\n"  /* ...1 .... .... .... */  
  47.         /*I(bit[12])=1 = Instruction cache enabled*/  
  48.     #endif    
  49.            
  50.         /* MMU enabled */  
  51.         "orr    r0, r0, #0x0001\n"      /* .... .... .... ...1 */  
  52.         /*M(bit[0])=1 = MMU enabled*/  
  53.         "mcr    p15, 0, r0, c1, c0, 0\n"    /* write control register */  
  54.         /*数据手册P545*/  
  55.         : /* no outputs */  
  56.     : "r" (ttb) );   
  57. }  

 

4、Step 4:heap_init()   
第4步调用了heap_init(void)函数,并返回值。该值是函数heap_init()调用的mmalloc_init()函数的返回值。其实,这步就是申请一块内存区域。

 
  1. [lib/heap.c->heap_init(void)]   
  2. int heap_init(void)   
  3. {   
  4.           return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);         
  5. }   

内存动态分配函数mmalloc就是从heap(堆)中划出一块空闲内存。相应的mfree函数则将动态分配的某块内存释放回heap中。
heap_init 函数在SDRAM中指定了一块1M大小的内存作为heap(起始地址HEAP_BASE = 0x33e00000),并在heap的开头定义了一个数据结构blockhead。事实上,heap就是使用一系列的blockhead数据结构来描述和操作的。每个blockhead数据结构对应着一块heap内存,假设一个blockhead数据结构的存放位置为A,则它对应的可分配内存地址为“A + sizeof(blockhead)”到“A + sizeof(blockhead) + size - 1”。blockhead数据结构在lib/heap.c中定义:

 
  1. typedef struct blockhead_t {   
  2.      int32 signature;     //固定为BLOCKHEAD_SIGNATURE   
  3.      bool allocated;      //此区域是否已经分配出去:0-N,1-Y   
  4.      unsigned long size;  //此区域大小   
  5.      struct blockhead_t *next;   //链表指针   
  6.      struct blockhead_t *prev;   //链表指针   
  7. } blockhead;  


现在来看看heap是如何运作的(如果您不关心heap实现的细节,这段可以跳过)。vivi对heap的操作比较简单,vivi中有一个全局变量 static blockhead *gHeapBase,它是heap的链表头指针,通过它可以遍历所有blockhead数据结构。假设需要动态申请一块sizeA大小的内存,则 mmalloc函数从gHeapBase开始搜索blockhead数据结构,如果发现某个blockhead满足:
(1) allocated = 0  //表示未分配
(2) size > sizeA,则找到了合适的blockhead,
满足上述条件后,进行如下操作:
a.allocated设为1
b.如果size – sizeA > sizeof(blockhead),则将剩下的内存组织成一个新的blockhead,放入链表中
c.返回分配的内存的首地址释放内存的操作更简单,直接将要释放的内存对应的blockhead数据结构的allocated设为0即可。
heap_init函数直接调用mmalloc_init函数进行初始化,此函数代码在lib/heap.c中,比较简单,初始化gHeapBase即可:

 
  1. [main(int argc, char *argv[]) > heap_init(void) > mmalloc_init(unsigned char *heap, unsigned long size)]   
  2. static inline int mmalloc_init(unsigned char *heap, unsigned long size)   
  3. {   
  4.     if (gHeapBase != NULL) return -1;   
  5.     DPRINTK("malloc_init(): initialize heap area at 0x%08lx, size = 0x%08lx\n", heap, size);   
  6.     gHeapBase = (blockhead *)(heap);   
  7.     gHeapBase->allocated=FALSE;   
  8.     gHeapBase->signature=BLOCKHEAD_SIGNATURE;   
  9.     gHeapBase->next=NULL;   
  10.     gHeapBase->prev=NULL;   
  11.     gHeapBase->size = size - sizeof(blockhead);   
  12.     return 0;   
  13. }   

 

static blockhead *gHeapBase = NULL; 这个就是上面称赞的全局变量了,定义在lib/heap.c中。上面就是个链表操作,数据结构,看来搞这个也得好好学数据结构啊,不然内存搞的溢出、浪费可就哭都来不及了。

5、Step 5:mtd_dev_init() 
所谓MTD(Memory Technology Device)相关的技术。在linux系统中,我们通常会用到不同的存储设备,特别是FLASH设备。为了在使用新的存储设备时,我们能更简便地提供它的驱动程序,在上层应用和硬件驱动的中间,抽象出MTD设备层。驱动层不必关心存储的数据格式如何,比如是FAT32、ETX2还是FFS2或其它。它仅仅提供一些简单的接口,比如读写、擦除及查询。如何组织数据,则是上层应用的事情。MTD层将驱动层提供的函数封装起来,向上层提供统一的接口。这样,上层即可专注于文件系统的实现,而不必关心存储设备的具体操作。这段乱七八糟的话也许比较让人晕,也可以这样理解在设备驱动(此处指存储设备)和上层应用之间还存在着一层,共三层,这个中间层就是MTD技术的产物。通常可以将它视为驱动的一部分,叫做上层驱动,而那些实现设备的读、写操作的驱动称为下层驱动,上层驱动将下层驱动封装,并且留给其上层应用一些更加容易简单的接口。
在我们即将看到的代码中,使用mtd_info数据结构表示一个MTD 设备,使用nand_chip数据结构表示一个nand flash芯片。在mtd_info结构中,对nand_flash结构作了封装,向上层提供统一的接口。比如,它根据nand_flash提供的 read_data(读一个字节)、read_addr(发送要读的扇区的地址)等函数,构造了一个通用的读函数read,将此函数的指针作为自己的一个成员。而上层要读写flash时,执行mtd_info中的read、write函数即可。
mtd_dev_init()用来扫描所使用的 NAND Flash的型号,构造MTD设备,即构造一个mtd_info的数据结构。对于S3C2410来说,它直接调用mtd_init(),mtd_init 又调用smc_init(),此函数在drivers/mtd/maps/s3c2410_flash.c中:

 
  1. [main(int argc,char *argv[])>mtd_dev_init()>mtd_init()]   
  2. int mtd_init(void)   
  3. {   
  4.     int ret;   
  5.        
  6.     #ifdef CONFIG_MTD_CFI                /*is not set*/   
  7.         ret = cfi_init();   
  8.     #endif   
  9.     #ifdef CONFIG_MTD_SMC9                /* =y */   
  10.         ret = smc_init();   
  11.     #endif   
  12.     #ifdef CONFIG_S3C2410_AMD_BOOT        /*is not set*/   
  13.         ret = amd_init();   
  14.     #endif   
  15.        
  16.     if (ret) {   
  17.         mymtd = NULL;   
  18.         return ret;   
  19.     }   
  20.     return 0;   
  21. }   

 

显而易见,该函数应取第二项,这项在autoconf.h中定义了。

 
  1. [main(int argc, char *argv[]) > mtd_dev_init() > mtd_init() > smc_init()]   
  2. static int  
  3. smc_init(void)   
  4. {   
  5.     /*struct mtd_info *mymtd,数据类型在include/mtd/mtd.h*/  
  6.     /*strcut nand_chip在include/mtd/nand.h中定义*/  
  7.     struct nand_chip *this;   
  8.     u_int16_t nfconf;   
  9.     /* Allocate memory for MTD device structure and private data */  
  10.     mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));   
  11.     if (!mymtd) {   
  12.         printk("Unable to allocate S3C2410 NAND MTD device structure.\n");   
  13.         return -ENOMEM;   
  14.     }   
  15.     /* Get pointer to private data */  
  16.     this = (struct nand_chip *)(&mymtd[1]);   
  17.     /* Initialize structures */  
  18.     memset((char *)mymtd, 0, sizeof(struct mtd_info));   
  19.     memset((char *)this, 0, sizeof(struct nand_chip));   
  20.     /* Link the private data with the MTD structure */  
  21.     mymtd->priv = this;   
  22.     /* set NAND Flash  controller */  
  23.     nfconf = NFCONF;   
  24.     /* NAND Flash controller enable */  
  25.     nfconf |= NFCONF_FCTRL_EN;   
  26.     /* Set flash memory timing */  
  27.     nfconf &= ~NFCONF_TWRPH1;   /* 0x0 */  
  28.     nfconf |= NFCONF_TWRPH0_3;  /* 0x3 */  
  29.     nfconf &= ~NFCONF_TACLS; /* 0x0 */  
  30.        
  31.     NFCONF = nfconf;   
  32.        
  33.     /* Set address of NAND IO lines */  
  34.     this->hwcontrol = smc_hwcontrol;   
  35.     this->write_cmd = write_cmd;   
  36.     this->write_addr = write_addr;   
  37.     this->read_data = read_data;   
  38.     this->write_data = write_data;   
  39.     this->wait_for_ready = wait_for_ready;   
  40.        
  41.     /* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */  
  42.     this->hwcontrol(NAND_CTL_SETNCE);   
  43.     this->write_cmd(NAND_CMD_RESET);   
  44.     this->wait_for_ready();   
  45.     this->hwcontrol(NAND_CTL_CLRNCE);   
  46.        
  47.     smc_insert(this);   
  48.        
  49.     return 0;   
  50. }   
  51.   

 

6 -14行构造了一个mtd_info结构和nand_flash结构,前者对应MTD设备,后者对应nand flash芯片(如果您用的是其他类型的存储器件,比如nor flash,这里的nand_flash结构应该换为其他类型的数据结构)。MTD设备是具体存储器件的抽象,那么在这些代码中这种关系如何体现呢——第 14行的代码把两者连结在一起了。事实上,mtd_info结构中各成员的实现(比如read、write函数),正是由priv变量所指向的 nand_flash的各类操作函数(比如read_addr、read_data等)来实现的。
15-20行是初始化S3C2410上的 NAND FLASH控制器。前面分配的nand_flash结构还是空的,现在当然就是填满它的各类成员了,这正是21-26行做的事情。27-30行对这块 nand flash作了一下复位操作。最后,也是最复杂的部分,根据刚才填充的nand_flash结构,构造mtd_info结构,这由31行的 smc_insert函数调用smc_scan完成。

这才是VIVI启动的第5步,还有三步就完成了启动了,同时我的这篇阅读笔记也就OVER了。

 
相关文章:
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