免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1379 | 回复: 0
打印 上一主题 下一主题

VIVI源码分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-16 00:04 |只看该作者 |倒序浏览

1.1 Vivi简介
Vivi 是韩国mizi 公司开发的bootloader, 适用于ARM9处理器。 Vivi有两种工作模式:启动加载模式和下载模式。启动加载模式可以在一段时间后(这个时间可更改)自行启动linux内核,这时vivi的默认模式。在下载模式下,vivi为用户提供一个命令行接口,通过接口可以使用vivi提供的一些命令,见下表:
命令
功能
Load
把二进制文件载入Flash或RAM
Part
操作MTD分区信息。显示、增加、删除、复位、保存MTD分区
Param
设置参数
Boot
启动系统
Flash
管理Flash,如删除Flash的数据
1.2 vivi的配置与编译
1.2.1 建立交叉开发环境
1、在宿主机上安装标准Linux 操作系统:Redhat 9.0。
2、宿主机上安装交叉编译器。
交叉编译器工具:arm-linux-gcc-2.95.3(源码为cross-2.95.3.tar.bz2)。然后修改PATH 变量:为了可以方便使用arm-linux-gcc编译器系统, 把arm-linux工具链目录加入到环境变量PATH中。
1.2.2 配置和编译vivi
       如果vivi的源代码已根据开发板作了相应改动,则需要对源代码进行配置和编译,以生成烧入flash的vivi 二进制映象文件。由于vivi要用到kernel的一些头文件,需要kernel的源代码,所以先要把linux的kernel准备好。将vivi和kernel都解到相应目录下。
      需修改/vivi/Makefile里的一些变量设置:
LINUX_INCLUDE_DIR = /kernel/include/
(LINUX_INCLUDE_DIR 为kernel/include的对应目录,我的是usr/src/linux-2.6.21.5/include)
因此修改为:
LINUX_INCLUDE_DIR = usr/src/linux-2.6.21.5/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。
1.3 vivi代码分析
vivi的代码包括arch,init,lib,drivers和include等几个目录,共200多条文件。
Vivi主要包括下面几个目录:
arch:此目录包括了所有vivi支持的目标板的子目录,例如s3c2410,s3c2440目录。
drivers:其中包括了引导内核需要的设备的驱动程序(MTD和串口)。MTD目录下分map、nand和nor三个目录。
init:这个目录只有main.c和version.c两个文件。和普通的C程序一样,vivi将从main函数开始执行。
lib:一些平台公共的接口代码,比如time.c里的udelay()和mdelay()。
include:头文件的公共目录,其中的s3c24xx.h定义了这块处理器的一些寄存器。Platform/smdk24xx.h定义了与开发板相关的资源配置参数,我们往往只需要修改这个文件就可以配置目标板的参数,如波特率、引导参数、物理内存映射等。
1.4 vivi的运行
vivi的运行也可以分为两个阶段:
1.4.1 vivi的第一阶段
完成含依赖于CPU的体系结构硬件初始化的代码,包括禁止中断、初始化串口、复制自身到RAM等。相关代码集中在head.S(viviarchs3c24xx目录下):Head.S:
#include "config.h"
#include "linkage.h"
#include "machine.h"
@ Start of executable code
ENTRY(_start)
ENTRY(ResetEntryPoint)
@
@ Exception vector table (physical address = 0x00000000)  ;异常向量表物理地址
@
@ 0x00: Reset ;复位
b     Reset
@ 0x04: Undefined instruction exception    ;未定义的指令异常
UndefEntryPoint:
b     HandleUndef
@ 0x08: Software interrupt exception    ;软件中断异常
SWIEntryPoint:
b     HandleSWI
@ 0x0c: Prefetch Abort (Instruction Fetch Memory Abort)  ;内存操作异常
PrefetchAbortEnteryPoint:
b     HandlePrefetchAbort
@ 0x10: Data Access Memory Abort    ;数据异常
DataAbortEntryPoint:
b     HandleDataAbort
@ 0x14: Not used       ;未使用
NotUsedEntryPoint:
b     HandleNotUsed
@ 0x18: IRQ(Interrupt Request) exception       ;慢速中断处理
IRQEntryPoint:
b     HandleIRQ
@ 0x1c: FIQ(Fast Interrupt Request) exception;快速中断处理
FIQEntryPoint:
b     HandleFIQ
@
@ VIVI magics
@
@ 0x20: magic number so we can verify that we only put
.long   0
@ 0x24:
.long   0
@ 0x28: where this vivi was linked, so we can put it in memory in the right place
.long   _start
@ 0x2C: this contains the platform, cpu and machine id
.long   ARCHITECTURE_MAGIC
@ 0x30: vivi capabilities
.long   0
#ifdef CONFIG_PM        ;vivi考虑不需要使用电源管理
@ 0x34:
b     SleepRamProc       ;子程序head.S中定义
#endif
#ifdef CONFIG_TEST
@ 0x38:
b     hmi                         ;子程序head.S中定义
#endif @
@ Start VIVI head
@
Reset:
@ disable watch dog timer
mov r1, #0x53000000      
mov r2, #0x0
str   r2, [r1]
@ disable all interrupts      ;禁止全部中断
       mov r1, #INT_CTL_BASE
       mov r2, #0xffffffff
       str   r2, [r1, #oINTMSK]        ;掩码关闭所有中断
       ldr   r2, =0x7ff
       str   r2, [r1, #oINTSUBMSK]
@ initialise system clocks         ;初始化系统时钟
mov r1, #CLK_CTL_BASE
mvn r2, #0xff000000
str   r2, [r1, #oLOCKTIME]
@initialise system clocks: fclk,hclk,pclk   
mov r1, #CLK_CTL_BASE   
ldr r2, clkdivn_value
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
mov r1, #CLK_CTL_BASE
@ldr r2, mpll_value   @ clock default
ldr  r2, =0x7f021 @mpll_value_USER   @ clock user set
str r2, [r1, #oMPLLCON]
bl    memsetup                                                              ;跳转到memsetup函数
/*****************************
Memsetup函数的实现:
ENTRY(memsetup)
@ initialise the static memory
@ set memory control registers    ;设置内存控制寄存器的初值
mov r1, #MEM_CTL_BASE
adrl r2, mem_cfg_val
add r3, r1, #52                            ;整整13个寄存器
1:    ldr   r4, [r2], #4
str   r4, [r1], #4
cmp r1, r3
bne  1b                                       ;循环操作,直到13个寄存器赋值完成
mov pc, lr
/*******************
@
@ Data Area
@
@ Memory configuration values
.align 4
mem_cfg_val:                          ;定义好的13*4=52个字节初值
.long       vBWSCON                ;在/vivi/include/platform/smdk24xx.h中赋值
/******   SDRAM从32位变成16位,需要修改vBWSCON的值 ******/
.long       vBANKCON0
.long       vBANKCON1
.long       vBANKCON2
.long       vBANKCON3
/**********  网卡控制器vBANKCON3的值可能需要修改  **************/
.long       vBANKCON4
.long       vBANKCON5
.long       vBANKCON6
/****** SDRAM从32位变成16位,可能需要修改vBANKCON6的值 ******/
.long       vBANKCON7
.long       vREFRESH
.long       vBANKSIZE
/****** SDRAM从64MB变成32MB,需要修改vBANKSIZE的值 ******/
.long       vMRSRB6
.long       vMRSRB7
********************/
#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                                      ;子程序head.S中定义
#endif
@ All LED on
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_F
ldr r2,=0x55aa
str r2, [r1, #oGPIO_CON]
mov r2, #0xff
str r2, [r1, #oGPIO_UP]
mov r2, #0x00
str r2, [r1, #oGPIO_DAT]
#if 0
@ SVC
mrs r0, cpsr
bic r0, r0, #0xdf
orr r1, r0, #0xd3
msr cpsr_all, r1
#endif
@ set GPIO for UART
#ifdef CONFIG_S3C2440_SMDK                  ;配置文件选择为Y
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_H
ldr r2, gpio_con_uart                                    ;0x0016faaa,根据你的硬件来配置
str r2, [r1, #oGPIO_CON]
ldr r2, gpio_up_uart
str r2, [r1, #oGPIO_UP]
#endif
bl InitUART
@ Initialize UART
@
@ r0 = number of UART port
InitUART:
ldr r1, SerBase
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 ((UART_PCLK  / (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
/*******************
.align 4                               ;缺省情况下在vivi中只初始化了UART0
SerBase:
#if defined(CONFIG_SERIAL_UART0)
.long UART0_CTL_BASE        ;基地址在/vivi/include/s3c24xx.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
/********************/
#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,
[email=#'@']#'@'[/email]
bl PrintChar
mov r0, pc
bl PrintHexWord
#endif

#ifdef CONFIG_S3C2440_NAND_BOOT
bl copy_myself                                                                @copy_myself 开始  

#ifdef CONFIG_S3C2440_NAND_BOOT
@
@ copy_myself: copy vivi to ram
@
copy_myself:
mov r10, lr
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =( (7#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)在smdk24xx.h中定义
mov     r1, #0x0                       @vivi拷贝的源地址
mov r2, #0x20000                   @vivi拷贝的长度,从NANDFlash的0地址拷贝128k到SDRAM指定处
bl nand_read_ll                       @nand_read_ll在/vivi/arch/s3c24xx/nand_read.c中定义
;r0,r1,r2分别为函数的三个参数
#if 1
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_F
mov r2, #0xb0
str r2, [r1, #oGPIO_DAT]
#endif
tst r0, #0x0                             @将第一操作数(需要测试的)与第二操作数位与,如果匹配则设置 Zero 标志。
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
#if 1
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_F
mov r2, #0x70
str r2, [r1, #oGPIO_DAT]
#endif
mov pc, r10                            @vivi拷贝到SDRAM完成,函数返回      @copy_myself 结束
#endif @ CONFIG_S3C2440_NAND_BOOT
/**************************************以下这段如何理解
@ jump to ram
    ldr r1, =on_the_ram
    add pc, r1, #0                     @SRAM中的VIVI自己从这里跳到SDRAM中的VIVI开始执行,由于两者一样,我们还
    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/s3c24xx/smdk.c文件中。开发板初始化主要完成两个功能,时钟初始化(init_time())和通用IO口设置(set_gpios())。其中,GPIO口在smdk24xx.h(vivi/include/platform目录下)文件中定义。
(3)内存映射初始化和内存管理单元的初始化工作:这两个函数都在/arch/s3c24xx/mmu.c文件中。
(4)初始化堆栈,heap_init()。(定义在vivi/lib/heap.c文件中)
(5)初始化mtd设备,mtd_dev_init()。这几个函数可以在/drivers/mtd/maps/s3c24xx_flash.c里找到。
(6) 初始化私有数据,init_priv_data()。(定义在vivilibpriv_datarw.c文件中)
(7) 初始化内置命令,init_builtin_cmds()。通过add_command函数,加载vivi内置的几个命令。
(8)启动boot_or_vivi()。
       启动成功后,将通过vivi_shell()启动一个shell(如果配置了CONFIG_SERIAL_TERM),此时vivi的任务完成。
Vivi的初始配置文件位置:/vivi/arch/def-configs/smkd24xx, 通过make menuconfig 修改后的配置保存在这个文件中,我们也可以载入一个自己的配置文件来进行编译。
原文地址
http://blog.163.com/liting_2006/blog/static/3193794720086834811675/


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/110004/showart_2150545.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP