Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2278659
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2008-06-04 07:53:59

简介

Vivi 是韩国mizi 公司开发的bootloader, 适用于ARM9处理器。 Vivi有两种工作模式:启动加载模式和下载模式。启动加载模式可以在一段时间后(这个时间可更改)自行启动linux内核,这时vivi的默认模式。在下载模式下,vivi为用户提供一个命令行接口,通过接口可以使用vivi提供的一些命令,见下表:

命令

功能

Load

把二进制文件载入FlashRAM

Part

操作MTD分区信息。显示、增加、删除、复位、保存MTD分区

Param

设置参数

Boot

启动系统

Flash

管理Flash,如删除Flash的数据

的配置与编译

1.2.1 建立交叉开发环境

1、在宿主机上安装标准Linux 操作系统:Redhat 9.0 ( 主机系统为win2000,用虚拟机vmware安装的Redhat 9.0,内核版本为2.4.18) 。

2、宿主机上安装交叉编译器。

我这边的2410开发板提供的光盘上已附交叉编译器工具:arm-linux-gcc-2.95.3(源码为cross-2.95.3.tar.bz2)。

先以root 用户的身份登陆到linux 下。

进入/usr/local 目录,创建名为arm的目录:

cd /usr/local

mkdir arm

将光盘提供的cross-2.95.3.tar.bz2解压到/usr/local/arm目录:

tar jxvf cross-2.95.3.tar.bz2 C /usr/local/arm

然后修改修改PATH 变量:为了可以方便使用arm-linux-gcc编译器系统, arm-linux工具链目录加入到环境变量PATH中:

修改/etc/profile文件,添加pathmunge /usr/local/arm/2.95.3/bin即可。

# Path manipulation

if [ `id -u` = 0 ]; then

pathmunge /sbin

pathmunge /usr/sbin

pathmunge /usr/local/sbin

pathmunge /usr/local/arm/2.95.3/bin

fi

pathmunge /usr/X11R6/bin after

设置环境变量后,最好是重启或注销一下,这样设置的环境变量才能生效。

1.2.2 配置和编译vivi

如果vivi的源代码已根据开发板作了相应改动,则需要对源代码进行配置和编译,以生成烧入flash的vivi 二进制映象文件。

由于vivi要用到kernel的一些头文件,所以需要kernel的源代码,所以先要把linuxkernel准备好。将vivikernel都解到相应目录下(例如我将光盘提供的vivi源代码解压到/home/chenjun目录下,光盘提供的Linux kernel源码kernel-h2410eb.041024.tar.gz也解压到/home/chenjun目录下,解压后的文件名为kerne-h2410eb)。

然后需修改/vivi/Makefile里的一些变量设置:

Ø LINUX_INCLUDE_DIR = /kernel/include/

LINUX_INCLUDE_DIR kernel/include的对应目录,我的是/home/chen/kerne-h2410eb /include/

因此修改为:

LINUX_INCLUDE_DIR = /home/chenjun/ kerne-h2410eb/include/

Ø CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

(CROSS_COMPILE arm-linux安装的相应目录,我的是/usr/local/arm/2.95.3/bin/arm-linux-)

因此修改为:

CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

Ø ARM_GCC_LIBS = /usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3

(需根据你arm-linux的安装目录修改,我的是/usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3

进入/vivi目录执行make distclean。(目的是确保编译的有效性,在编译之前将vivi里所有的“*.o”“*.o.flag”文件删掉)

进入/vivi目录里,输入“make menuconfig”,开始选择配置。可以Load一个写好的配置文件也可以自己修改试试。注意Exit时一定要选“Yes”保存配置。

再输入“make”正式开始编译,一会儿就完了。如果不报错,在/vivi里面就有你自己的“vivi”了。这个就是后面要烧写到flash中的bootloader

Bootloader(Vivi)源代码分析

----基于S3C2410处理器

作者:forkchen

Email:chenjun@bupt-bcnl.com

QQ:56155986

欢迎广大嵌入式之友多多交流

目 录

简介

Vivi 是韩国mizi 公司开发的bootloader, 适用于ARM9处理器。 Vivi有两种工作模式:启动加载模式和下载模式。启动加载模式可以在一段时间后(这个时间可更改)自行启动linux内核,这时vivi的默认模式。在下载模式下,vivi为用户提供一个命令行接口,通过接口可以使用vivi提供的一些命令,见下表:

命令

功能

Load

把二进制文件载入FlashRAM

Part

操作MTD分区信息。显示、增加、删除、复位、保存MTD分区

Param

设置参数

Boot

启动系统

Flash

管理Flash,如删除Flash的数据

的配置与编译

1.2.1 建立交叉开发环境

1、在宿主机上安装标准Linux 操作系统:Redhat 9.0 ( 主机系统为win2000,用虚拟机vmware安装的Redhat 9.0,内核版本为2.4.18) 。

2、宿主机上安装交叉编译器。

我这边的2410开发板提供的光盘上已附交叉编译器工具:arm-linux-gcc-2.95.3(源码为cross-2.95.3.tar.bz2)。

先以root 用户的身份登陆到linux 下。

进入/usr/local 目录,创建名为arm的目录:

cd /usr/local

mkdir arm

将光盘提供的cross-2.95.3.tar.bz2解压到/usr/local/arm目录:

tar jxvf cross-2.95.3.tar.bz2 C /usr/local/arm

然后修改修改PATH 变量:为了可以方便使用arm-linux-gcc编译器系统, arm-linux工具链目录加入到环境变量PATH中:

修改/etc/profile文件,添加pathmunge /usr/local/arm/2.95.3/bin即可。

# Path manipulation

if [ `id -u` = 0 ]; then

pathmunge /sbin

pathmunge /usr/sbin

pathmunge /usr/local/sbin

pathmunge /usr/local/arm/2.95.3/bin

fi

pathmunge /usr/X11R6/bin after

设置环境变量后,最好是重启或注销一下,这样设置的环境变量才能生效。

1.2.2 配置和编译vivi

如果vivi的源代码已根据开发板作了相应改动,则需要对源代码进行配置和编译,以生成烧入flash的vivi 二进制映象文件。

由于vivi要用到kernel的一些头文件,所以需要kernel的源代码,所以先要把linuxkernel准备好。将vivikernel都解到相应目录下(例如我将光盘提供的vivi源代码解压到/home/chenjun目录下,光盘提供的Linux kernel源码kernel-h2410eb.041024.tar.gz也解压到/home/chenjun目录下,解压后的文件名为kerne-h2410eb)。

然后需修改/vivi/Makefile里的一些变量设置:

Ø LINUX_INCLUDE_DIR = /kernel/include/

LINUX_INCLUDE_DIR kernel/include的对应目录,我的是/home/chen/kerne-h2410eb /include/

因此修改为:

LINUX_INCLUDE_DIR = /home/chenjun/ kerne-h2410eb/include/

Ø CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

(CROSS_COMPILE arm-linux安装的相应目录,我的是/usr/local/arm/2.95.3/bin/arm-linux-)

因此修改为:

CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

Ø ARM_GCC_LIBS = /usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3

(需根据你arm-linux的安装目录修改,我的是/usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3

进入/vivi目录执行make distclean。(目的是确保编译的有效性,在编译之前将vivi里所有的“*.o”“*.o.flag”文件删掉)

进入/vivi目录里,输入“make menuconfig”,开始选择配置。可以Load一个写好的配置文件也可以自己修改试试。注意Exit时一定要选“Yes”保存配置。

再输入“make”正式开始编译,一会儿就完了。如果不报错,在/vivi里面就有你自己的“vivi”了。这个就是后面要烧写到flash中的bootloader

mvn r2, #0xff000000


 

       str   r2, [r1, #oLOCKTIME]


 


 

       @ldr      r2, mpll_50mhz


 

       @str       r2, [r1, #oMPLLCON]


 

#ifndef CONFIG_S3C2410_MPORT1                               ;满足条件,向下执行


 

/**** /vivi/include/autoconf.h#undef  CONFIG_S3C2410_MPORT1******/


 

       @ 1:2:4


 

       mov r1, #CLK_CTL_BASE


 

       mov r2, #0x3


 

       str   r2, [r1, #oCLKDIVN]


 


 

       mrc p15, 0, r1, c1, c0, 0           @ read ctrl register


 

       orr   r1, r1, #0xc0000000          @ Asynchronous 


 

       mcr p15, 0, r1, c1, c0, 0           @ write ctrl register


 


 

       @ now, CPU clock is 200 Mhz                             CPU的频率是200MHz


 

       mov r1, #CLK_CTL_BASE


 

       ldr   r2, mpll_200mhz


 

       str   r2, [r1, #oMPLLCON]


 

#else


 

       @ 1:2:2


 

    mov r1, #CLK_CTL_BASE


 

    ldr r2, clock_clkdivn


 

    str r2, [r1, #oCLKDIVN]


 


 

    mrc p15, 0, r1, c1, c0, 0       @ read ctrl register


 

    orr r1, r1, #0xc0000000     @ Asynchronous


 

    mcr p15, 0, r1, c1, c0, 0       @ write ctrl register


 


 

    @ now, CPU clock is 100 Mhz                                   CPU的频率是100MHz


 

    mov r1, #CLK_CTL_BASE


 

    ldr r2, mpll_100mhz


 

    str r2, [r1, #oMPLLCON]


 

#endif


 

       bl    memsetup                                                              ;跳转到memsetup函数


 

/*****************************


 

Memsetup函数的实现:


 

ENTRY(memsetup)


 

       @ initialise the static memory


 


 

       @ set memory control registers                       ;设置内存控制寄存器的初值


 

       mov r1, #MEM_CTL_BASE


 

       adrl r2, mem_cfg_val


 

/*******************


 

@


 

@ Data Area


 

@


 

@ Memory configuration values


 

.align 4


 

mem_cfg_val:                                                                                                                       ;定义好的13*4=52个字节初值


 

       .long       vBWSCON                ;在/vivi/include/platform/smdk2410.h中赋值


 

/******   SDRAM32位变成16位,需要修改vBWSCON的值 ******/


 

       .long       vBANKCON0


 

       .long       vBANKCON1


 

       .long       vBANKCON2


 

       .long       vBANKCON3


 

/**********  网卡控制器vBANKCON3的值可能需要修改  **************/


 

       .long       vBANKCON4


 

       .long       vBANKCON5


 

       .long       vBANKCON6


 

/****** SDRAM32位变成16位,可能需要修改vBANKCON6的值 ******/


 

       .long       vBANKCON7


 

       .long       vREFRESH


 

       .long       vBANKSIZE


 

/****** SDRAM64MB变成32MB,需要修改vBANKSIZE的值 ******/


 

       .long       vMRSRB6


 

       .long       vMRSRB7


 

********************/


 

       add r3, r1, #52


 

1:    ldr   r4, [r2], #4


 

       str   r4, [r1], #4


 

       cmp r1, r3


 

       bne  1b                                      ;循环操作,直到13个寄存器赋值完成


 


 

       mov pc, lr


 

*******************************/


 

#ifdef CONFIG_PM                        vivi考虑不需要使用电源管理


 

       @ Check if this is a wake-up from sleep 


 

       ldr   r1, PMST_ADDR


 

       ldr   r0, [r1]


 

       tst    r0, #(PMST_SMR)


 

       bne  WakeupStart                      ;查看状态,判断是否需要跳转到WakeupStart


 

#endif


 


 


 

#ifdef CONFIG_S3C2410_SMDK                      SMDK开发板使用


 

       @ All LED on                                                ;点亮开发板上的LED


 

       mov r1, #GPIO_CTL_BASE


 

       add r1, r1, #oGPIO_F                                   LED使用GPIOF组的管脚


 

ldr   r2,=0x55aa                 ;使能EINT0EINT1EINT2EINT3


 

;另四个管脚配置成输出,屏蔽EINT4567


 

       str   r2, [r1, #oGPIO_CON]


 

       mov r2, #0xff


 

       str   r2, [r1, #oGPIO_UP]         disable the pull-up function


 

       mov r2, #0x00


 

       str   r2, [r1, #oGPIO_DAT]


 

#endif


 


 

#if 0


 

       @ SVC


 

       mrs  r0, cpsr


 

       bic   r0, r0, #0xdf


 

       orr   r1, r0, #0xd3


 

       msr  cpsr_all, r1


 

#endif


 


 

       @ set GPIO for UART                                   ;设置串口


 

       mov r1, #GPIO_CTL_BASE


 

       add r1, r1, #oGPIO_H                                   ;设置GPIO_H组管脚为串口


 

       ldr   r2, gpio_con_uart


 

       str   r2, [r1, #oGPIO_CON]


 

       ldr   r2, gpio_up_uart


 

       str   r2, [r1, #oGPIO_UP] 


 

/*************************


 

@ inital values for GPIO


 

gpio_con_uart:


 

       .long       vGPHCON   vGPHCON/vivi/include/platform/smdk2410.h中赋值


 

                                          #define vGPHCON               0x0016faaa


 

                                          GPIO_H配置为nCTS0nRTS0, RXD0,TXD0, RXD1


 

TXD1nCTS1nRTS1,


 


 

/****  三个串口都使能,可能需要修改#define vGPHCON 0x0016aaaa   ****/


 


 

gpio_up_uart:


 

       .long       Vgphup         ;同上#define vGPHUP                  0x000007ff


 

                                          ;The pull-up function is disabled.


 

************************/


 


 

       bl    InitUART             ;跳转到InitUART串口初始化函数


 

/****************************************************

@ Initialize UART


@


@ r0 = number of UART port


InitUART:


ldr r1, SerBase


/*******************


.align 4 ;缺省情况下在vivi中只初始化了UART0


SerBase:


#if defined(CONFIG_SERIAL_UART0)


.long UART0_CTL_BASE ;基地址在/vivi/include/s3c2410.h中定义


#elif defined(CONFIG_SERIAL_UART1)


.long UART1_CTL_BASE


#elif defined(CONFIG_SERIAL_UART2)


.long UART2_CTL_BASE


#else


#error not defined base address of serial


#endif


********************/


mov r2, #0x0


str r2, [r1, #oUFCON]


str r2, [r1, #oUMCON]


mov r2, #0x3


str r2, [r1, #oULCON]


ldr r2, =0x245


str r2, [r1, #oUCON]


#define UART_BRD ((50000000 / (UART_BAUD_RATE * 16)) - 1)


mov r2, #UART_BRD


str r2, [r1, #oUBRDIV]



mov r3, #100


mov r2, #0x0


1: sub r3, r3, #0x1


tst r2, r3


bne 1b



#if 0


mov r2, #'U'


str r2, [r1, #oUTXHL]



1: ldr r3, [r1, #oUTRSTAT]


and r3, r3, #UTRSTAT_TX_EMPTY


tst r3, #UTRSTAT_TX_EMPTY


bne 1b



mov r2, #'0'


str r2, [r1, #oUTXHL]



1: ldr r3, [r1, #oUTRSTAT]


and r3, r3, #UTRSTAT_TX_EMPTY


tst r3, #UTRSTAT_TX_EMPTY


bne 1b


#endif



mov pc, lr


****************************************************/



#ifdef CONFIG_DEBUG_LL ;打印调试信息,缺省未定义


@ Print current Program Counter


ldr r1, SerBase


mov r0, #'\r'


bl PrintChar


mov r0, #'\n'


bl PrintChar


mov r0, #'@'


bl PrintChar


mov r0, pc


bl PrintHexWord


#endif




#ifdef CONFIG_BOOTUP_MEMTEST


@ simple memory test to find some DRAM flaults.


bl memtest


#endif



#ifdef CONFIG_S3C2410_NAND_BOOT ;从NAND Flash启动


bl copy_myself ;跳转到copy_myself函数


/**********************************************


@


@ copy_myself: copy vivi to ram


@


copy_myself:


mov r10, lr



@ reset NAND


mov r1, #NAND_CTL_BASE


ldr r2, =0xf830 @ initial value


str r2, [r1, #oNFCONF]


ldr r2, [r1, #oNFCONF]


bic r2, r2, #0x800 @ enable chip


str r2, [r1, #oNFCONF]


mov r2, #0xff @ RESET command


strb r2, [r1, #oNFCMD]


mov r3, #0 @ wait


1: add r3, r3, #0x1


cmp r3, #0xa


blt 1b


2: ldr r2, [r1, #oNFSTAT] @ wait ready


tst r2, #0x1


beq 2b


ldr r2, [r1, #oNFCONF]


orr r2, r2, #0x800 @ disable chip


str r2, [r1, #oNFCONF]



@ get read to call C functions (for nand_read())


ldr sp, DW_STACK_START @ setup stack pointer


mov fp, #0 @ no previous frame, so fp=0



@ copy vivi to RAM


ldr r0, =VIVI_RAM_BASE


/*********/vivi/linux/platform/smdk2410.h中定义


#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)


***************************************/


mov r1, #0x0


mov r2, #0x20000 0x20000-128k字节


bl nand_read_ll nand_read_ll/vivi/arch/s3c2410/nand_read.c中定义


r0,r1,r2分别为函数的三个参数


;从NANDFlash0地址拷贝128kSDRAM指定处


tst r0, #0x0


beq ok_nand_read


#ifdef CONFIG_DEBUG_LL


bad_nand_read:


ldr r0, STR_FAIL


ldr r1, SerBase


bl PrintWord


1: b 1b @ infinite loop


#endif



ok_nand_read:


#ifdef CONFIG_DEBUG_LL


ldr r0, STR_OK


ldr r1, SerBase


bl PrintWord


#endif

@ verify


mov r0, #0


ldr r1, =0x33f00000


mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes


go_next:


ldr r3, [r0], #4


ldr r4, [r1], #4


teq r3, r4


bne notmatch


subs r2, r2, #4


beq done_nand_read


bne go_next


notmatch:


#ifdef CONFIG_DEBUG_LL


sub r0, r0, #4


ldr r1, SerBase


bl PrintHexWord


ldr r0, STR_FAIL


ldr r1, SerBase


bl PrintWord


#endif


1: b 1b


done_nand_read:



#ifdef CONFIG_DEBUG_LL


ldr r0, STR_OK


ldr r1, SerBase


bl PrintWord


#endif



mov pc, r10 vivi拷贝到SDRAM完成,函数返回


*********************************/


@ jump to ram


ldr r1, =on_the_ram


add pc, r1, #0


nop


nop


1: b 1b @ infinite loop



on_the_ram:


#endif



#ifdef CONFIG_DEBUG_LL


ldr r1, SerBase


ldr r0, STR_STACK


bl PrintWord


ldr r0, DW_STACK_START


bl PrintHexWord


#endif



@ get read to call C functions


ldr sp, DW_STACK_START @ setup stack pointer


mov fp, #0 @ no previous frame, so fp=0


mov a2, #0 @ set argv to NULL



bl main @ call main



mov pc, #FLASH_BASE @ otherwise, reboot



@


@ End VIVI head


@




1.4.2 vivi的第二阶段


vivi的第二阶段是从main()函数开始,同一般的C语言程序一样,该函数在/init/main.c文件中,总共可以分为8个步骤。


(1) 函数开始,通过putstr(vivi_banner)打印出vivi的版本。Vivi_banner/init/version.c文件中定义


(2) 对开发板进行初始化(board_init函数),board_init是与开发板紧密相关的,这个函数在/arch/s3c2410/smdk.c文件中。开发板初始化主要完成两个功能,时钟初始化(init_time())和通用IO口设置(set_gpios())。


void set_gpios(void)


{


GPACON = vGPACON;


GPBCON = vGPBCON;


GPBUP = vGPBUP;


GPCCON = vGPCCON;


GPCUP = vGPCUP;


GPDCON = vGPDCON;


GPDUP = vGPDUP;


GPECON = vGPECON;


GPEUP = vGPEUP;


GPFCON = vGPFCON;


GPFUP = vGPFUP;


GPGCON = vGPGCON;


GPGUP = vGPGUP;


GPHCON = vGPHCON;


GPHUP = vGPHUP;


EXTINT0 = vEXTINT0;


EXTINT1 = vEXTINT1;


EXTINT2 = vEXTINT2;


}


其中,GPIO口在smdk2410.h\vivi\include\platform\目录下)文件中定义。


(3) 内存映射初始化和内存管理单元的初始化工作:


mem_map_init();


mmu_init();


这两个函数都在/arch/s3c2410/mmu.c文件中。


void mem_map_init(void)


{


#ifdef CONFIG_S3C2410_NAND_BOOT


mem_map_nand_boot();


#else


mem_map_nor();


#endif


cache_clean_invalidate();


tlb_invalidate();


}



如果配置vivi时使用了NAND作为启动设备,则执行mem_map_nand_boot(),否则执行mem_map_nor()。这里要注意的是,如果使用NOR启动,则必须先把vivi代码复制到RAM中。这个过程是由copy_vivi_to_ram()函数来完成的。代码如下:
static void copy_vivi_to_ram(void)


{


putstr_hex("Evacuating 1MB of Flash to DRAM at 0x", VIVI_RAM_BASE);


memcpy((void *)VIVI_RAM_BASE, (void *)VIVI_ROM_BASE, VIVI_RAM_SIZE);


}


VIVI_RAM_BASEVIVI_ROM_BASEVIVI_RAM_SIZE这些值都可以在smdk2410.h中查到,并且这些值必须根据自己开发板的RAM实际大小修改。这也是在移植vivi的过程中需要注意的一个地方。


mmu_init()函数中执行了arm920_setup函数。这段代码是用汇编语言实现的,针对arm920t核的处理器。



(4) 初始化堆栈,heap_init()。(定义在\vivi\lib\heap.c文件中)


int heap_init(void)


{


return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);


}


(5) 初始化mtd设备,mtd_dev_init()


int mtd_init(void)


{


int ret;



#ifdef CONFIG_MTD_CFI


ret = cfi_init();


#endif


#ifdef CONFIG_MTD_SMC


ret = smc_init();


#endif


#ifdef CONFIG_S3C2410_AMD_BOOT


ret = amd_init();


#endif



if (ret) {


mymtd = NULL;


return ret;


}


return 0;


}


这几个函数可以在/drivers/mtd/maps/s3c2410_flash.c里找到。


(6) 初始化私有数据,init_priv_data()。(定义在\vivi\lib\priv_data\rw.c文件中)


(7) 初始化内置命令,init_builtin_cmds()


通过add_command函数,加载vivi内置的几个命令。


(8) 启动boot_or_vivi()


启动成功后,将通过vivi_shell()启动一个shell(如果配置了CONFIG_SERIAL_TERM),此时vivi的任务完成。


启动代码执行流程图




(1)head.s代码执行流程 (2)main.c代码执行流程





的配置文件



Vivi的初始配置文件位置:/vivi/arch/def-configs/smkd2410, 通过make menuconfig 修改后的配置保存在这个文件中,我们也可以载入一个自己的配置文件来进行编译。

阅读(930) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~