当前位置:首页 > 单片机 > 单片机
[导读]建议读一读《嵌入式系统Boot Loader技术内幕》(詹荣开著),google一下就会找到一片。什么是Bootloader就不再这里废话了,看看上面的文章就明了了。 Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,r

建议读一读《嵌入式系统Boot Loader技术内幕》(詹荣开著),google一下就会找到一片。什么是Bootloader就不再这里废话了,看看上面的文章就明了了。 Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,redboot,lilo等等。Vivi 是韩国mizi公司专门为三星s3c2410芯片设计的Bootloader。

先来看看vivi的源码树:

vivi-+-arch-+-s3c2410

|-Documentation

|-drivers-+-serial

| ‘-mtd-+-maps

| |-nor

| ‘-nand

|-include-+-platform

| |-mtd

| ‘-proc

|-init

|-lib-+-priv_data

|-scripts-+-lxdialog

|-test

|-util

可以google一下,搜到源码vivi.tar.gz。

前面提到的文件已经系统的分析了bootloader的,这里就按源代码来具体说事。vivi也可以分为2个阶段,阶段1的代码在arch/s3c2410/head.S中,阶段2的代码从init/main.c的main函数开始。

阶段1

阶段1从程序arch/s3c2410/head.S开始,按照head.S的代码执行顺序,一次完成了下面几个任务:

1、关WATCH DOG (disable watch dog timer)

上电后,WATCH DOG默认是开着的

2、禁止所有中断 (disable all interrupts)

vivi中不会用到中断,中断是系统的事,bootloader可不能去干这事的(不过这段代码实在多余,上电后中断默认是关闭的)

3、初始化系统时钟(initialise system clocks)

启动MPLL,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为“Asynchronous bus mode”。

4、初始化内存控制寄存器(memsetup)

S3c2410共有15个寄存器,在此开始初始化13个寄存器。

5、检查是否从掉电模式唤醒(Check if this is a wake-up from sleep)

若是,则调用WakeupStart函数进行处理。

6、点亮所有LED (All LED on)

点一下灯,通知外面的同志,告诉他们有情况发生。

7、初始化UART0 (set GPIO for UART & InitUART)

a.设置GPIO,选择UART0使用的引脚

b.初始化UART0,设置工作方式(使用FIFO)、波特率115200 8N1、无流控等。这可是使用串口与s3c2410通信的条件啊,在终端也要如此设置。

8、跳到内存测试函数(simple memory test to find some DRAM flaults)

当然要定义了CONFIG_BOOTUP_MEMTEST这个参数才会跳到内存测试。

9、如果定义了以Nand flash方式启动(#ifdef CONFIG_S3C2410_NAND_BOOT),则此时要将vivi所有代码(包括阶段1和阶段2)从Nand flash复制到SDRAM中(因为在Nand flash中是不能执行程序的,它只能做为程序和数据的存储器,而Nor flash可就不同了,Nor flash可以执行程序,但贵是它发展得瓶颈):

a.设置nand flash控制寄存器

b.设置堆栈指针

c.设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单位)

d.调用nand_read_ll进行复制

  10、跳到bootloader的阶段2运行,亦即调用init/main.c中的main函数(get read to call C functions)

a.重新设置堆栈

b.设置main函数的参数

c.调用main函数

head.S有900多行,都是些arm汇编,看的云山雾罩,汇编看来是忘的差不多了,所以这部分代码也看的相当糙,只知道大概在干什么,至于个中缘由就不是很了解。先学学arm汇编再回来看。

阶段2

从init/main.c中的main函数开始,终于步入C语言的世界了。Main函数总共有8步(8 steps),先看看源代码:

int main(int argc, char *argv[])

{

int ret;

/*

* Step 1:

*/

putstr("rn");

putstr(vivi_banner); //vivi_banner是vivi执行开始的显示信息,vivi_banner在文件version.c中定义

reset_handler();

/*

* Step 2:

*/

ret = board_init();

if (ret) {

putstr("Failed a board_init() procedurern");

error();

}

/*

* Step 3:

*/

mem_map_init();

mmu_init();

putstr("Succeed memory mapping.rn");

/*

* Now, vivi is running on the ram. MMU is enabled.

* Step 4:

*/

/* initialize the heap area*/

ret = heap_init();

if (ret) {

putstr("Failed initailizing heap regionrn");

error();

}

/* Step 5:

* MTD

*/

ret = mtd_dev_init();

/* Step 6:

*/

init_priv_data();

/* Step 7:

*/

misc();

init_builtin_cmds();

/* Step 8:

*/

boot_or_vivi();

return 0;

}

下面按照上面的步骤逐步来分析一下。

1、Step 1:reset_handler()

reset_handler用于将内存清零,代码在lib/reset_handle.c中。

1 void

2 reset_handler(void)

3 {

4 int pressed;

5 pressed = is_pressed_pw_btn(); /*判断是硬件复位还是软件复位*/

6 if (pressed == PWBT_PRESS_LEVEL) {

7 DPRINTK("HARD RESETrn");

8 hard_reset_handle(); /*调用clear_mem对SDRAM清0*/

9 } else {

10 DPRINTK("SOFT RESETrn");

11 soft_reset_handle(); /*此函数为空*/

12 }

13 }

在上电后,reset_handler调用第8行的hard_reset_handle(),此函数在lib/reset_handle.c中:

[main(int argc, char *argv[]) -> reset_handler() -> hard_reset_handle()]

1 static void

2 hard_reset_handle(void)

3 {

4 #if 0

5 clear_mem((unsigned long)(DRAM_BASE + VIVI_RAM_ABS_POS),

6 (unsigned long)(DRAM_SIZE - VIVI_RAM_ABS_POS));

7 #endif

/*lib/memory.c,将起始地址为USER_RAM_BASE,长度为USER_RAM_SIZE的内存清0*/

8 clear_mem((unsigned long)USER_RAM_BASE, (unsigned long) USER_RAM_SIZE);

9 }

先写到这儿吧。

(未完待续)

S3C2410 bootloader ----VIVI阅读笔记2(续笔记1)

2、Step 2:board_init()

board_init调用2个函数用于初始化定时器和设置各GPIO引脚功能,代码在arch/s3c2410/smdk.c中:

[main(int argc, char *argv[]) > board_init()]

1 int board_init(void)

2 {

3 init_time(); /*arch/s3c2410/proc.c*/

4 set_gpios(); /*arch/s3c2410/smdk.c */

5 return 0;

6 }

init_time() 这个函数对寄存器进行了简单的操作:

void init_time(void)

{

TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));

/*s3c2410 data sheet P298*/

/*TCFG0 = 0 | 0xf00 | 0 */

}

寄存器TCFG0由三部分组成,prescaler0,prescaler1,deadzone和reserve四部分,前三部分分别对应 TCFG0_PRE0、TCFG0_PRE1、TCFG0_DZONE,TCFG0_PRE0(0)实际值为0x00,TCFG0_PRE1(15)实际值为0x0f00,而TCFG0_DZONE(0)实际值为 0x000000。实际中,vivi并未使用定时器,这个函数就可以忽略。set_gpios()用于选择GPA至GPH端口各引脚的功能及是否使用各引脚的内部上拉电阻,并设置外部中断源寄存器EXTINT0-2(vivi中未使用外部中断)。

1 void set_gpios(void)

2 {

3 GPACON = vGPACON;

4 GPBCON = vGPBCON;

5 GPBUP = vGPBUP;

6 GPCCON = vGPCCON;

7 GPCUP = vGPCUP;

8 GPDCON = vGPDCON;

9 GPDUP = vGPDUP;

10 GPECON = vGPECON;

11 GPEUP = vGPEUP;

12 GPFCON = vGPFCON;

13 GPFUP = vGPFUP;

14 GPGCON = vGPGCON;

15 GPGUP = vGPGUP;

16 GPHCON = vGPHCON;

17 GPHUP = vGPHUP;

18 EXTINT0 = vEXTINT0;

19 EXTINT1 = vEXTINT1;

20 EXTINT2 = vEXTINT2;

21 }

以第三行为例,vGPACON的值为0x007fffff,查找s3c2410用户手册可知,该参数将GPACON的23位全部置1。各位功能需察看s3c2410用户手册

3、Step 3:建立页表和启动MMU

mem_map_init();

mmu_init();

mem_map_init函数用于建立页表,vivi使用段式页表,只需要一级页表。它调用3个函数,代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mem_map_init(void)]

1 void mem_map_init(void)

2 {

3 #ifdef CONFIG_S3C2410_NAND_BOOT

/*CONFIG_S3C2410_NAND_BOOT = y ,在文件include/autoconf.h中定义*/

4 mem_map_nand_boot();

/* 最终调用mem_mepping_linear, 建立页表 */

5 #else

6 mem_map_nor();

7 #endif

8 cache_clean_invalidate();/* 清空cache,使无效cache */

9 tlb_invalidate(); /* 使无效快表TLB */

10 }

第9、 10行的两个函数可以不用管它,他们做的事情在下面的mmu_init函数里又重复了一遍。对于本开发板,在.config中定义了 CONFIG_S3C2410_NAND_BOOT。mem_map_nand_boot()函数调用mem_mapping_linear()函数来最终完成建立页表的工作。页表存放在SDRAM物理地址0x33dfc000开始处,共16K:一个页表项4字节,共有4096个页表项;每个页表项对应 1M地址空间,共4G。mem_map_init先将4G虚拟地址映射到相同的物理地址上,NCNB(不使用cache,不使用write buffer)――这样,对寄存器的操作跟未启动MMU时是一样的;再将SDRAM对应的64M空间的页表项修改为使用cache。 mem_mapping_linear函数的代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mem_map_init(void) > mem_map_nand_boot( ) > mem_mapping_linear(void)]

1 static inline void mem_mapping_linear(void)

2 {

3 unsigned long pageoffset, sectionNumber;

4 putstr_hex("MMU table base address = 0x", (unsigned long)

mmu_tlb_base);

5 /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, not bufferable */

6 /* mmu_tlb_base = 0x33dfc000*/

7 for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {

8 pageoffset = (sectionNumber << 20);

9 *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset |

MMU_SECDESC;

10 }

11 /* make dram cacheable */

12 /* SDRAM物理地址0x3000000-0x33ffffff,

13 DRAM_BASE=0x30000000,DRAM_SIZE=64M

14 */

15 for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE);

16 pageoffset += SZ_1M) {

17 //DPRINTK(3, "Make DRAM section cacheable: 0x%08lxn", pageoffset);

18 *(mmu_tlb_base + (pageoffset >> 20)) =

pageoffset | MMU_SECDESC | MMU_CACHEABLE;

19 }

20 }

mmu_init()函数用于启动MMU,它直接调用arm920_setup()函数。arm920_setup()的代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mmu_init( ) > arm920_setup( )]

1 static inline void arm920_setup(void)

2 {

3 unsigned long ttb = MMU_TABLE_BASE;

/* MMU_TABLE_BASE = 0x33dfc000 */

4 __asm__(

5 /* Invalidate caches */

6 "mov r0, #0n"

7 "mcr p15, 0, r0, c7, c7, 0n" /* invalidate I,D caches on v4 */

8 "mcr p15, 0, r0, c7, c10, 4n" /* drain write buffer on v4 */

9 "mcr p15, 0, r0, c8, c7, 0n" /* invalidate I,D TLBs on v4 */

10 /* Load page table pointer */

11 "mov r4, %0n"

12 "mcr p15, 0, r4, c2, c0, 0n" /* load page table pointer */

13 /* Write domain id (cp15_r3) */

14 "mvn r0, #0n" /* Domains 0b01 = client, 0b11=Manager*/

15 "mcr p15, 0, r0, c3, c0, 0n"

/* load domain access register,write domain 15:0

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

  引言   汽车的普及为人们的生活带来了方便,同时也给人们提出了一大难题——汽车防盗。本设计是为了解决以往汽车防盗产品的缺点和不足而开发的集成传感、报警和远程图

关键字: 数据采集 操作系统 s3c2410 汽车防盗系统

  引言   巡航控制系统(CCS)是20世纪60年代发展起来的,又称为恒速行驶系统。巡航控制系统工作时,ECU根据各种传感器输送来的信号判断汽车的运行状况,通过执行元件自动调节节气门的

关键字: ARM 三星 Linux ecu s3c2410 电子控制系统

  在过去一百年里(l906-2005),全球地表平均温度升高了0.74摄氏度,未来20年,每十年全球温度将会升高0.2摄氏度。气候变暖已成为不容忽视的、直接影响全球生产和生活问题。  

关键字: can总线 s3c2410

  在此设计的基于 GPRS 的远程安防监控系统,是采用的是摄像机传送视频信号经压缩编码后,通过内部总线传送到内置的 Web 服务器。用户在监控端可以直接通过浏览器观看 Web服务器上的摄像机视

关键字: GPRS s3c2410 安防监控

  随着半导体技术的不断进步(按照摩尔定律),MCU内部集成的逻辑功能外设越来越多,存储器也越来越大。消费者对于汽车节能(经济和法规对排放的要求)型、舒适性、互联性、安全性(功能安全和信息安全)

关键字: bootloader 汽车电子

1.之所以要实现一个专用的bootloader,一是为了更好的移植和自身的升级,二是为了方便操作系统的调试,当然,你完全可以将这部分所要实现的与操作系统相关的功能集成到操作

关键字: bootloader 如何实现 嵌入式开发

网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的驱动程序,有感于刚接...

关键字: Linux s3c2410 dma驱动

1引言目前 , 在嵌入式系统里基于ARM核的嵌入式处理器已经成为市场主流。随着ARM技术的广泛应用 , 建立面向ARM构架的嵌入式操作系统也就成为当前研究的热点。S3C2410是SAMSUNG公司基于ARM920T处理器...

关键字: s3c2410 移植 标准linux

一、S3C2410支持4种供电模式(1)NORMAL MODE耗电最大、可以通过关闭具体控制器的时钟来节电(2)SLOW MODE在此模式下可以没有内部PLL,耗电情况依赖于外部时钟的频率(3)IDLE MODEFCLK...

关键字: s3c2410 电源管理
关闭
关闭