本文仅探讨s3c6410从nand flash启动u-boot时的代码重定位过程

参考:

1)《USER'S MANUAL-S3C6410X》第二章 MEMORY MAP 第八章 NAND FLASH CONTROLLER

2)u-boot源码:

u-boot-x.x.x/board/samsumg/smdk6410/lowlevel_init.S

u-boot-x.x.x/cpu/s3c64xx/start.S

u-boot-x.x.x/cpu/s3c64xx/nand_cp.c

代码重定位过程简述

由于在nand flash中无法运行代码,所以当开发板从nand flash启动时,我们需要将存储在外设nand flash中的u-boot代码搬运到sdram中运行,如何完成这个搬运工作呢?这需要借助一个跳板,即“stepping stone”,它是s3c6410的一块内置sram,开发板上电时,nand flash控制器自动将nand flash的前8K的内容拷贝到sram中并执行,这一小段启动代码除了初始化硬件外,最重要的一个工作就是将nand flash中的所有u-boot代码拷贝(即重定位)到sdram的指定地址上去,然后跳转到sdram中执行。

重定位代码解析:

1)nand接口初始化

u-boot启动时,首先执行相应硬件平台的start.S,start.S中调用lowlevel_init对时钟,uart,nand,mmu等底层硬件作初始化。

start.S:

...
bl lowlevel_init /* go setup pll,mux,memory */
...

lowlevel_init.S:

...
/*
* Nand Interface Init for SMDK6400 */
nand_asm_init:
ldr r0, =ELFIN_NAND_BASE
ldr r1, [r0, #NFCONF_OFFSET]
orr r1, r1, #0x70
orr r1, r1, #0x7700
str r1, [r0, #NFCONF_OFFSET] ldr r1, [r0, #NFCONT_OFFSET]
orr r1, r1, #0x03
str r1, [r0, #NFCONT_OFFSET] mov pc, lr
...

2)代码重定位

从nand flash启动时,重定位代码如下:

start.S:

/* when we already run in ram, we don't need to relocate U-Boot.
* and actually, memory controller must be configured before U-Boot
* is running in ram.
*/
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */ #ifdef CONFIG_BOOT_NAND
mov r0, #0x1000
bl copy_from_nand
#endif

r1存放当前代码运行的起始地址,r2存放u-boot即将在sdram中运行的地址,如果两个地址相等,说明此时u-boot已经在sdram中运行了,无需再执行从nand拷贝数据到sdram的动作;否则,此时u-boot还在它的临时住所sram中执行,此地不可久留,需要执行copy_from_nand将u-boot代码完完整整地拷贝到sdram中去,然后跳转到sdram中去执行剩下的代码。

/*
* copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)
* r0: size to be compared
* Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size
*/
.globl copy_from_nand
copy_from_nand:
mov r10, lr /* save return address */ mov r9, r0
/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #
mov fp, # /* no previous frame, so fp=0 */
mov r9, #0x1000
bl copy_uboot_to_ram : tst r0, #0x0
bne copy_failed ldr r0, =0x0c000000
ldr r1, _TEXT_PHY_BASE
: ldr r3, [r0], #
ldr r4, [r1], #
teq r3, r4
bne compare_failed /* not matched */
subs r9, r9, #
bne 1b : mov lr, r10 /* all is OK */
mov pc, lr copy_failed:
nop /* copy from nand failed */
b copy_failed compare_failed:
nop /* compare failed */
b compare_failed

真正执行拷贝动作的是copy_uboot_to_ram函数,它定义在u-boot-x.x.x/cpu/s3c64xx/nand_cp.c中,

int copy_uboot_to_ram (void)
{
int large_block = ;
int i;
vu_char id; NAND_ENABLE_CE();
NFCMD_REG = NAND_CMD_READID;
NFADDR_REG = 0x00; /* wait for a while */
for (i=; i<; i++);
id = NFDATA8_REG;
id = NFDATA8_REG; if (id > 0x80)
large_block = ; /* read NAND Block.
* 128KB ->240KB because of U-Boot size increase. by scsuh
* So, read 0x3c000 bytes not 0x20000(128KB).
*/
return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);
}

nand flash支持两种页大小,512B和2KB,large_block = 0时,页大小为512字节,large_block = 1时,页大小为2K字节。nandll_read_blocks拷贝nand flash从第0页开始的0x3c00(240K)大小的数据到sdram的CFG_PHY_UBOOT_BASE地址处。

/*
* Read data from NAND.
*/
static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
uchar *buf = (uchar *)dst_addr;
int i;
uint page_shift = ; if (large_block)
page_shift = ; /* Read pages */
for (i = ; i < (0x3c000>>page_shift); i++, buf+=(<<page_shift)) {
nandll_read_page(buf, i, large_block);
} return ;
}

首先根据large_block判断nand flash一个页的大小,从而计算需要拷贝的页的数量,即需要拷贝(0x3c000>>page_shift)个页,nandll_read_page每次只拷贝一个页的数据。

/*
* address format
* 17 16 9 8 0
* --------------------------------------------
* | block(12bit) | page(5bit) | offset(9bit) |
* --------------------------------------------
*/ static int nandll_read_page (uchar *buf, ulong addr, int large_block)
{
int i;
int page_size = ; if (large_block)
page_size = ; NAND_ENABLE_CE(); NFCMD_REG = NAND_CMD_READ0; /* Write Address */
NFADDR_REG = ; if (large_block)
NFADDR_REG = ; NFADDR_REG = (addr) & 0xff;
NFADDR_REG = (addr >> ) & 0xff;
NFADDR_REG = (addr >> ) & 0xff; if (large_block)
NFCMD_REG = NAND_CMD_READSTART; NF_TRANSRnB(); /* for compatibility(2460). u32 cannot be used. by scsuh */
for(i=; i < page_size; i++) {
*buf++ = NFDATA8_REG;
} NAND_DISABLE_CE();
return ;
}

从nand flash中读取数据的流程为片选(NAND_ENABLE_CE)->发读命令(NFCMD_REG)->发地址(NFADDR_REG)->发读命令(NFCMD_REG)->等待数据可读(NF_TRANSRnB)->读数据(NFDATA8_REG)。由于每次从NFDATA8_REG中只可读取1个字节的数据,所以拷贝一页需要读取512或2048次。

当执行完copy_uboot_to_ram返回到start.S时,nand flash中的代码重定位便完成了,此后程序跳转到sdram中执行,stepping stone的职责就此结束。

s3c6410_uboot中的代码重定位(nand->sdram)的更多相关文章

  1. S3C2440—10.代码重定位

    文章目录 一.启动方式 1.1 NAND FLASH 启动 1.2 NOR FLASH 启动 二. 段的概念 2.1 重定位数据段 2.2 加载地址的引出 三.链接脚本 3.1 链接脚本的引入 3.2 ...

  2. 【图片+代码】:GCC 链接过程中的【重定位】过程分析

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  3. 代码重定位和位置无关码——运行于nor flash

    通过前面的学习,我们知道,把可执行程序从一个位置复制到另一个位置的过程叫做重定位. 现在有两种方式,第一种是只重定位data段到内存(sdram),为什么需要重定位?因为有些flash的写操作,不是简 ...

  4. s3c2440裸机-代码重定位(1.重定位的引入,为什么要代码重定位)

    1.重定位的引入(为什么要代码重定位) 我们知道s3c2440的cpu从0地址开始取指令执行,当从nor启动时,0地址对应nor,nor可以像内存一样读,但不能像内存一样写.我们能够从nor上取指令执 ...

  5. s3c2440裸机-代码重定位、清bss的改进和位置无关码

    1.代码重定位的改进 用ldr.str代替ldrb, strb加快代码重定位的速度. 前面重定位时,我们使用的是ldrb命令从的Nor Flash读取1字节数据,再用strb命令将1字节数据写到SDR ...

  6. s3c2440裸机-代码重定位(2.编程实现代码重定位)

    代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata ...

  7. Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...

  8. U-Boot中关于TEXT_BASE,代码重定位,链接地址相关说明

    都知道U-BOOT分为两个阶段,第一阶段是(~/cpu/arm920t/start.S中)在FLASH上运行(一般情况 下),完成对硬件的初始化,包括看门狗,中断缓存等,并且负责把代码搬移到SDRAM ...

  9. uboot 与 代码重定位

    ref: https://blog.csdn.net/dhauwd/article/details/78566668 https://blog.csdn.net/yueqian_scut/articl ...

随机推荐

  1. StateMachine

    Create State Machine Create either a passive or an active state machine: ? 1 var fsm = new PassiveSt ...

  2. 程序员遇到Bug时的30个反应

    开发应用程序是一个非常有压力的工作.没有人是完美的,因此在这个行业中,代码中出现bug是相当普遍的现象.面对bug,一些程序员会生气,会沮丧,会心烦意乱,甚至会灰心丧气,而另一些程序员会依然保持冷静沉 ...

  3. 看oracle版本

    源地址:http://www.cnblogs.com/wolfplan/p/3876164.html select * from v$version;

  4. jsp标准标签库

    抄袭自:http://www.cnblogs.com/hongten/archive/2011/05/14/2046005.html JSP标准标签库     Pass by xkk ,and aut ...

  5. FAQ: Automatic Statistics Collection (文档 ID 1233203.1)

    In this Document   Purpose   Questions and Answers   What kind of statistics do the Automated tasks ...

  6. 《Code Complete》ch.26 代码调整技术

    WHAT? 提高代码运行速度的方法,减少代码的资源占用 WHY? 这里提出的都是“可以尝试的”方法,有的或许在你的环境根本不起作用,有的则能实实在在产生很好的效果 HOW? Logic - 逻辑 在知 ...

  7. android 如何设置背景的透明度

    半透明<Button android:background="#e0000000" ... />透明<Button android:background=&quo ...

  8. 【caffe-windows】 caffe-master 之 classfication_demo.m 超详细分析

    classification_demo.m 是个很好的学习资料,了解这个代码之后,就能在matlab里用训练好的model对输入图像进行分类了,而且我在里边还学到了oversample的实例,终于了解 ...

  9. 游戏服务器生成全局唯一ID的几种方法

    在服务器系统开发时,为了适应数据大并发的请求,我们往往需要对数据进行异步存储,特别是在做分布式系统时,这个时候就不能等待插入数据库返回了取自动id了,而是需要在插入数据库之前生成一个全局的唯一id,使 ...

  10. Cesium简介

    一.Cesium介绍 Cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎.Cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区域,并提供良好的触摸支持 ...