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 #
意思是将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 #endif2)。.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分析方法如上所述。
问题解决。