S3C2410 bootloader ----VIVI阅读笔记 (转)下

1 static inline void mem_mapping_linear(void)
2 {
3      unsigned long pageoffset, sectionNumber;
4            putstr_hex("MMU table base address = 0x", (unsigned long)
mmu_tlb_base);
5       /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, not bufferable */
6       /* mmu_tlb_base = 0x33dfc000*/
7       for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {
8               pageoffset = (sectionNumber << 20);
9                 *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset |
            MMU_SECDESC;
10      }
11      /* make dram cacheable */
12      /* SDRAM物理地址0x3000000-0x33ffffff,
13          DRAM_BASE=0x30000000,DRAM_SIZE=64M
14      */
15      for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE); \
16          pageoffset += SZ_1M) {
17          //DPRINTK(3, "Make DRAM section cacheable: 0x%08lx\n",             pageoffset);
18          *(mmu_tlb_base + (pageoffset >> 20)) = \
pageoffset | MMU_SECDESC | MMU_CACHEABLE;
19      }
20 }
mmu_init()函数用于启动MMU,它直接调用arm920_setup()函数。arm920_setup()的代码在arch/s3c2410/mmu.c中:
[main(int argc, char *argv[]) > mmu_init( ) > arm920_setup( )]
1 static inline void arm920_setup(void)
2 {
3                  unsigned long ttb = MMU_TABLE_BASE;
/* MMU_TABLE_BASE = 0x33dfc000 */
4 __asm__(
5       /* Invalidate caches */
6       "mov    r0, #0\n"
7       "mcr    p15, 0, r0, c7, c7, 0\n"    /* invalidate I,D caches on v4 */
8       "mcr    p15, 0, r0, c7, c10, 4\n"   /* drain write buffer on v4 */
9       "mcr    p15, 0, r0, c8, c7, 0\n"    /* invalidate I,D TLBs on v4 */
           10      /* Load page table pointer */
11      "mov    r4, %0\n"
12      "mcr    p15, 0, r4, c2, c0, 0\n"    /* load page table pointer */
13      /* Write domain id (cp15_r3) */
          14      "mvn    r0, #0\n"    /* Domains 0b01 = client, 0b11=Manager*/
          15      "mcr    p15, 0, r0, c3, c0, 0\n"
/* load domain access register,write domain 15:0, 用户手册P548(access permissions)*/
16      /* Set control register v4 */
17      "mrc    p15, 0, r0, c1, c0, 0\n"    /* get control register v4 */
            /*数据手册P545:read control register */
18      /* Clear out 'unwanted' bits (then put them in if we need them) */
19      /* ..VI ..RS B... .CAM */   /*这些位的含义在数据手册P546*/
20      "bic r0, r0, #0x3000\n" /* ..11 .... .... .... */
            /*I(bit[12])=0 = Instruction cache disabled*/
21      /*V[bit[13]](Base location of exception registers)=0 = Low addresses = 0x0000 0000*/
22      "bic r0, r0, #0x0300\n"      /* .... ..11 .... .... */
23      /*R(ROM protection bit[9])=0*/
                   /*S(System protection bit[8])=0*/
                   /*由于TTB中AP=0b11(line141),所以RS位不使用(P579)*/
24      "bic r0, r0, #0x0087\n"      /* 0x0000000010000111 */
                /*M(bit[0])=0 = MMU disabled*/
                /*A(bit[1])=0 =Data address alignment fault checking disable*/
                /*C(bit[2])=0 = Data cache disabled*/
                /*B(bit[7])=0= Little-endian operation*/
25      /* Turn on what we want */
26      /* Fault checking enabled */
27      "orr r0, r0, #0x0002\n"      /* .... .... .... ..10 */
            /*A(bit[1])=1 = Data address alignment fault checking enable*/
28                  #ifdef CONFIG_CPU_D_CACHE_ON     /*is not set*/
29      "orr    r0, r0, #0x0004\n"      /* .... .... .... .100 */
            /*C(bit[2])=1 = Data cache enabled*/
30 #endif
31 #ifdef CONFIG_CPU_I_CACHE_ON     /*is not set*/
32      "orr    r0, r0, #0x1000\n" /* ...1 .... .... .... */
            /*I(bit[12])=1 = Instruction cache enabled*/
33 #endif
34          /* MMU enabled */
35                "orr    r0, r0, #0x0001\n"      /* .... .... .... ...1 */
            /*M(bit[0])=1 = MMU enabled*/
36                "mcr    p15, 0, r0, c1, c0, 0\n"    /* write control register */
            /*数据手册P545*/
37                : /* no outputs */
38                : "r" (ttb) );
39 }
[未完]
S3C2410 bootloader ----VIVI阅读笔记3
4、Step 4:heap_init()     
第4步调用了heap_init(void)函数,并返回值。该值是函数heap_init()调用的mmalloc_init()函数的返回值。其实,这步就是申请一块内存区域。
[lib/heap.c->heap_init(void)]
1        int heap_init(void)
2        {
3                return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);      
4        }
内存动态分配函数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即可:
[main(int argc, char *argv[]) > heap_init(void) > mmalloc_init(unsigned char *heap, unsigned long size)]
1         static inline int mmalloc_init(unsigned char *heap, unsigned long size)
2         {
3      if (gHeapBase != NULL) return -1;
    4    DPRINTK("malloc_init(): initialize heap area at 0x%08lx, size = 0x%08lx\n", heap, size);
5       gHeapBase = (blockhead *)(heap);
6       gHeapBase->allocated=FALSE;
7       gHeapBase->signature=BLOCKHEAD_SIGNATURE;
8       gHeapBase->next=NULL;
9       gHeapBase->prev=NULL;
10      gHeapBase->size = size - sizeof(blockhead);
11      return 0;
12         }
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中:
[main(int argc,char *argv[])>mtd_dev_init()>mtd_init()]
1        int mtd_init(void)
2 {
3 int ret;
4 #ifdef CONFIG_MTD_CFI                /*is not set*/
5 ret = cfi_init();
6        #endif
7        #ifdef CONFIG_MTD_SMC9                /* =y */
8                ret = smc_init();
9        #endif
10        #ifdef CONFIG_S3C2410_AMD_BOOT        /*is not set*/
11                ret = amd_init();
12        #endif
13        if (ret) {
14                mymtd = NULL;
15                return ret;
16                 }
17        return 0;
18        }
显而易见,该函数应取第二项,这项在autoconf.h中定义了。
[main(int argc, char *argv[]) > mtd_dev_init() > mtd_init() > smc_init()]
1 static int
2 smc_init(void)
3 {
/*struct mtd_info *mymtd,数据类型在include/mtd/mtd.h*/
            /*strcut nand_chip在include/mtd/nand.h中定义*/
4       struct nand_chip *this;
5       u_int16_t nfconf;
            /* Allocate memory for MTD device structure and private data */
6       mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));
7       if (!mymtd) {
8          printk("Unable to allocate S3C2410 NAND MTD device structure.\n");
9          return -ENOMEM;
10      }
            /* Get pointer to private data */
11      this = (struct nand_chip *)(&mymtd[1]);
            /* Initialize structures */
12      memset((char *)mymtd, 0, sizeof(struct mtd_info));
13      memset((char *)this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
14      mymtd->priv = this;
/* set NAND Flash controller */
15      nfconf = NFCONF;
/* NAND Flash controller enable */
16      nfconf |= NFCONF_FCTRL_EN;
/* Set flash memory timing */
17      nfconf &= ~NFCONF_TWRPH1;   /* 0x0 */
    18      nfconf |= NFCONF_TWRPH0_3; /* 0x3 */
    19      nfconf &= ~NFCONF_TACLS; /* 0x0 */
    20      NFCONF = nfconf;
            /* Set address of NAND IO lines */
    21      this->hwcontrol = smc_hwcontrol;
    22      this->write_cmd = write_cmd;
23      this->write_addr = write_addr;
24      this->read_data = read_data;
25      this->write_data = write_data;
26      this->wait_for_ready = wait_for_ready;
/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */
27      this->hwcontrol(NAND_CTL_SETNCE);
28      this->write_cmd(NAND_CMD_RESET);
29      this->wait_for_ready();
30      this->hwcontrol(NAND_CTL_CLRNCE);
31      smc_insert(this);
32      return 0;
33 }
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完成。

转载于:https://www.cnblogs.com/hnrainll/archive/2011/05/18/2050603.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华南理工网络计算机基础知识,2019年华南理工大学网络教育计算机基础随堂练习题第一章.docx...

计算机基础知识第一节 计算机的基本概念随堂练习提交截止时间&#xff1a;2019-06-15 23:59:59本次练习有题&#xff0c;你已做题&#xff0c;已提交题&#xff0c;其中答对题。当前页有6题&#xff0c;你已做6题&#xff0c;已提交6题&#xff0c;其中答对6题。1.(单选题)? 计…

orm jdbc_Spring Data JDBC通用DAO实现–迄今为止最轻量的ORM

orm jdbc我很高兴宣布Spring Data JDBC存储库项目的第一个版本。 这个开源库的目的是为基于Spring框架中 JdbcTemplate关系数据库提供通用&#xff0c;轻量且易于使用的DAO实现&#xff0c;与项目的Spring Data 框架兼容。 设计目标 轻巧&#xff0c;快速且开销低。 只有少数几…

NOIP模拟测试9「随·单·题」

liu_runda出的题&#xff0c;先$\%\%\%\%\%\%\%\%\%\%\%$为敬 随 考试时没有Qj 然后甚至没做,甚至没交 我不知道我怎么想的 这个题挺难改 你需要用到 循环矩阵快速幂,矩阵快速幂优化,打表找规律的基础 题解 首先我们可以列出来一个普通的dp式子 设f为第i次操作,操作后x变为j的概…

es5直接引入html文件,ES6+转ES5(webpack+babel、指定多个js文件、自动注入)

接续上篇ES6转ES5&#xff0c;本篇将使用webpack和babel将多个不同目录下指定的多个ES6语法的js文件编译为ES5&#xff0c;并将编译后的文件配置注入对应的html文件。一、新建项目&#xff0c;目录如下二、执行命令初始化项目cnpm init -y执行成功后会生成文件&#xff1a;pack…

在Spring MVC中,InternalResourceViewResolver做什么?

InternalResourceViewResolver是Spring MVC框架中ViewResolver一个实现&#xff0c;它将逻辑视图名称&#xff08;例如“ hello”&#xff09;解析为内部物理资源&#xff08;例如Servlet和JSP文件&#xff0c;例如放置在WEB-INF文件夹下的jsp文件&#xff09;。 它是UrlBasedV…

深圳敏捷云计算机科技,敏捷云 | 关于我们 | 敏捷云

(93) Afghanistan(355) Albania(213) Algeria(1) American Samoa(376) Andorra(244) Angola(1) Anguilla(1) Antigua(54) Argentina(374) Armenia(297) Aruba(61) 澳大利亚(43) Austria(994) Azerbaijan(973) Bahrain(880) Bangladesh(1) Barbados(375) Belarus(32) Belgium(50…

算法:用户喜好--Map与List配合下的查找

提示&#xff1a;在算法处理过程中&#xff0c;未必就要将出现在前面的作为关键字检索。比如本题&#xff0c;非得先去检索范围&#xff0c;再去判断范围中key的个数。反其道而行&#xff0c;把输入的数字当作关键字&#xff0c;组成Map package test;import java.util.ArrayLi…

带有Gradle的Spring Boot Web应用程序

1.简介 在继续使用Gradle创建演示Spring Boot Web应用程序之前&#xff0c;我假设我们已经准备好使用Gradle设置 。 摇篮设置指南 Gradle官方网站 2.创建演示应用程序 现在我们已经准备好安装插件&#xff0c;创建一个新的Gradle项目&#xff0c;如下所示– 单击下一步 &am…

html定义变量的语句规则,前端规范

前言&#xff1a;不规范的开发不仅使日后代码维护变的困难&#xff0c;同时也不利于团队的合作。下面列出了前端开发规范通用规范&#xff1a;1、前端工具统一sublime text&#xff0c;配置信息统一&#xff0c;如下&#xff1a;{"caret_style": "phase",&…

云技术-SaaS架构初步理解

最近公司准备整一个SaaS的东西。有幸参入这一块东西的搭建&#xff0c;借着這个机会也重新好好梳理了一下对SaaS的认识。今天整理一下&#xff01; 一、云计算与SaaS 说起SaaS&#xff0c;就得先说说云计算了。关于云计算分为三层&#xff0c;基础设施在最下端&#xff0c;平台…

primefaces_轻量级Web应用程序框架:PrimeFaces(JSF)+ Guice + MyBatis(第2部分)

primefaces在这一部分中&#xff0c;我将继续演示JSF&#xff0c;Guice和MyBatis的集成。 在持久层中使用DBCP连接池和MYSQL数据库。 看一下第1部分 。 在上一篇文章中 &#xff0c;我们创建了一个ServletContextListener。 现在&#xff0c;我们只需要在contextInitialized方…

html三元运算符 模板,AngularJS模板中的三元运算符

小编典典更新 &#xff1a;Angular1.1.5添加了一个三元运算符&#xff0c;因此现在我们可以简单地编写如果您使用的是较早版本的Angular&#xff0c;则有两个选择&#xff1a;(condition && result_if_true || !condition && result_if_false){true: result_if…

pycharm 更改创建文件默认路径

pycharm 更改创建文件默认路径 1、操作 依次找到以下路径修改为自己想要的路径即可&#xff1a;PyCharm——>Settings——>Appearance&Behavior——>System Setting——>Project Opening——>Default directory 2、图示 posted on 2019-07-29 14:18 初妍 阅…

Spring Security和多个过滤器链

Spring Security是一项非常有用的技术。 它使您可以保护应用程序而不会过于侵入&#xff0c;并允许插入许多不同的身份验证机制。 另一方面&#xff0c;要使用它并不是那么容易&#xff0c;并且每次接触它时我都必须重新学习这些工具之一。 在这篇文章中&#xff0c;我将介绍Sp…

计算机网络相关论文目录怎么弄,如何给你的标书、论文编页码和目录-论文页码设置...

一、如何从任意一页开始编码无论是做标书&#xff0c;还是写论文&#xff0c;都有一个给word文档编页码的问题。一般封面、目录、内容提要等前几页不要页码&#xff0c;页码从正文开始编起&#xff1b;或者前面内容编不同于正文的页码&#xff0c;或其中的某一页用罗马数字的页…

关于我

我的博客一般没有密码,有的话密码也是:znsbc, 写博客很少放题干,既然你搜到这个题解那么你肯定知道题干再搜的这个题 另外由于博主过于弱,所以博客难题会很少 借用$lnc$一句话&#xff08; WA0的快感&#xff0c;让我难以自拔。&#xff09; 另外由于博主写博客时大多神志不清…

NOIP模拟测试10「大佬·辣鸡·模板」

大佬 显然假期望 我奇思妙想出了一个式子$f[i]f[i-1]\sum\limits_{j1}^{j<m} C_{k \times j}^{k}\times w[j]$ 然后一想不对得容斥 于是我得到$f[i]f[i-1]\sum\limits_{j1}^{j<m} C_{j\times(k-1)}^{k-1} \times w[j]$ 但还是不对 现在思考第一个式子为什么不对 我们枚举…

activemq 持久订阅_ActiveMQ群集,持久订阅者和虚拟主题可助您一臂之力

activemq 持久订阅因此&#xff0c;您希望使用ActiveMQ跨分布式主题进行发布-订阅&#xff0c;并且要可靠。 您可以使用永久订阅&#xff0c;对吗&#xff1f; 可以&#xff0c;但是&#xff0c;如果您将群集与ActiveMQ一起使用&#xff0c;则可能会遇到意外的行为。 我最近在一…

会计电算化算不算计算机专业,成都会计学校会计电算化专业介绍

由于会计的火热&#xff0c;有很多同学都在咨询老师想要了解成都会计学校会计电算化专业&#xff0c;老师也整理了相关内容为同学们作为参考&#xff0c;希望对同学们有所帮助。就是将计算机信息技术应用到会计实务中&#xff0c;实现对会计信息的管理。会计电算化从20世纪50年…

给APK签名,修改签名

简介&#xff1a; 本来是不需要签名的&#xff0c;但是我有个android的专用设备&#xff0c;限制安装&#xff0c;但是售后给我通过了一个证书的验证。 那么我想装什么软件&#xff0c;就需要这个证书验证。 现在记录一下签名的主要过程&#xff0c;还有修改签名的方法。 一&am…