问题:
通过串口终端进入到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虚拟内存分配区—隔离带—高端内存映射区—专用页面映射区—保留区。
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
#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
分析方法如上所述。
问题解决。