S3C6410开发板real6410 Uboot中内存地址的映射计算

问题:

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

SMDK6410 # pri
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虚拟内存分配区隔离带高端内存映射区专用页面映射区保留区。

S3C6410开发板real6410 Uboot中内存地址的映射计算_第1张图片

物理地址映射区在物理上是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。

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
分析方法如上所述。


问题解决。




你可能感兴趣的:(内存分配)