uboot中的内存映射

今天在给路由器刷openwrt时,看着那些刷机教程的指令,突然觉得不对,小路由器板子上只有32M内存,4MFLASH,哪来0x80000000那么大的内存地址,想了一会,对了,uboot程序中好像是对MMU单元做了初始化,所以是可以使用虚拟内存的。

问题:
通过串口终端进入到Uboot命令行模式,输入printenv查看目标板上环境变量当前设定的值,结果如下:

SMDK6410 # print
bootcmd=nand read c0008000 40000 300000;bootm c0008000  
bootdelay=3  
baudrate=115200  
ethaddr=00:22:12:34:56:90  
ipaddr=192.168.1.20  
serverip=192.168.1.178  
gatewayip=192.168.1.1  
netmask=255.255.255.0  
bootargs=noinitrd console=ttySAC0 ubi.mtd=1 root=ubi0:rootfs rootfstype=ubifs init=/linuxrc video=fb:WX4300F ppp=none  
stdin=serial  
stdout=serial  
stderr=serial  

Environment size: 355/16380 bytes  
SMDK6410 #  

其中,bootcmd=nand read c0008000 40000 300000;bootm c0008000
意思是将nand flash中从0x40000起始地址处读取0x300000即3M字节的数据到RAM地址0xc0008000中,然后从内存地址0xc0008000处执行程序。
问题在于,S3C6410所分配的物理地址是0x5000_0000~0x5fff_ffff,总共是256M,恰好对应实际所挂载的内存D10163两片,Uboot访问的内存地址远远高于实际的物理内存地址。
那么,Uboot是如何使用内存地址0xc000_8000访问到实际的物理内存的呢?

解决办法:
1. 0xc000_8000是MMU初始化之后,系统读取到的内核地址空间。
一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分——用户空间和内核空间,用户空间占据3G(0x0000_0000~0xbffff_ffff),内核空间占据1G(0xc000_0000~0xffff_ffff)。
3~4G之间的内核空间中,从低地址到高地址依次为:物理内存映射区—隔离带—vmalloc虚拟内存分配区—隔离带—高端内存映射区—专用页面映射区—保留区。

物理地址映射区在物理上是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。
2. S3C6410的底层初始化是通过文件board\samsung\smdk6410\lowlevel_init.S来实现的。
该文件依次完成了关看门狗、清中断、初始化系统时钟、初始化串口、初始化nand flash、初始化内存控制器和初始化MMU。

MMU的初始化代码:

#ifdef CONFIG_ENABLE_MMU  
/*  
 * MMU Table for SMDK6400  
 */  

    /* form a first-level section entry */  
.macro FL_SECTION_ENTRY base,ap,d,c,b  
    .word (\base << 20) | (\ap << 10) | \  
          (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)  
.endm  

.section .mmudata, "a"  
    .align 14  
    /* the following alignment creates the mmu table at address 0x4000. */  
    .globl mmu_table  
mmu_table:  
    .set __base, 0  
    /* 1:1 mapping for debugging */  
    .rept 0xA00  
    FL_SECTION_ENTRY __base, 3, 0, 0, 0  
    .set __base, __base + 1  
    .endr  

    /* access is not allowed. */  
    .rept 0xC00 - 0xA00  
    .word 0x00000000  
    .endr  

    /* 128MB for SDRAM 0xC0000000 -> 0x50000000 */  
    .set __base, 0x500  
    .rept 0xC80 - 0xC00  
    FL_SECTION_ENTRY __base, 3, 0, 1, 1  
    .set __base, __base + 1  
    .endr  

    /* access is not allowed. */  
    .rept 0x1000 - 0xc80  
    .word 0x00000000  
    .endr  
#endif  

1)。确认成立条件

#if !defined(CONFIG_NAND_SPL) && (TEXT_BASE >= 0xc0000000)  
#define CONFIG_ENABLE_MMU  
#endif  

2)。.macro

/*  
 * MMU Table for SMDK6400  
 */  

    /* form a first-level section entry */  
.macro FL_SECTION_ENTRY base, ap, d, c, b  
    .word (\base << 20) | (\ap << 10) | \  
          (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)  
.endm    //结束宏定义  

看看伪指令的格式:

MACRO{$label}    macroname    {$parameter1} {$parameter2} ...  
//label宏展开时可以替换的符号  
//macroname 宏名  
//parameter n 宏指令的参数  
这里宏的名字为 FL_SECTION_ENTRY,其实可以看成C语言的 #define。

3)。制作映射表

.section .mmudata, "a"  
    .align 14    //按照 2^14 = 16384 对齐,即 0x4000  
    /* the following alignment creates the mmu table at address 0x4000. */  
    .globl mmu_table  
mmu_table:  
    .set __base, 0  //赋值为 0  
    /* 1:1 mapping for debugging */  
    .rept 0xA00    //重复次数 0xA00 = 2560  
    FL_SECTION_ENTRY __base, 3, 0, 0, 0  
    //代入公式得 FL_SECTION_ENTRY(起始) = (0b11 << 10) | (0b1 << 4) | (0b1 << 1)  
                        =  0x0000_4000(对齐后)  
    .set __base, __base + 1  
    //每一次 __base + 1 之后, FL_SECTION_ENTRY + 0x0010_0000 ,即 1MB   
    //所以此次制表范围是 2560MB  
    //从 0x0000_4000 ~ 0x9FF0_4000  
    .endr  

不可访问的区域,全部置为0。

274     /* access is not allowed. */  
275     .rept 0xC00 - 0xA00  //重复次数 0x200 = 512  
276     .word 0x00000000    //从0x9FF0_4000 ~ 0xBFF0_4000  
277     .endr  
278   

实际物理内存SDRAM映射。

/* 128MB for SDRAM 0xC0000000 -> 0x50000000 */  
    //这里为128MB,在实际使用中应该为256MB  
    .set __base, 0x500  
    .rept 0xC80 - 0xC00  //重复次数 0x80 = 128  
    //为256MB时应更改为 0xD00 - 0xC00   
    FL_SECTION_ENTRY __base, 3, 0, 1, 1  
    //代入公式得  FL_SECTION_ENTRY(起始) = 0xBFF0_4000  
    //此次制表范围 128MB  
    //从 0xBFF0_4000 ~ 0xC7F0_4000  
    .set __base, __base + 1  
    .endr  

不可访问区域,全部置为0。

286     /* access is not allowed. */  
287     .rept 0x1000 - 0xc80  //重复次数 0x380 = 896  
288     .word 0x00000000    //从0xC7F04000 ~ 0xFFF0_4000  
289 .endr     
290#endif  

分析方法如上所述。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值