Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2842018
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: LINUX

2009-06-30 22:27:45

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的代码包括archinitlibdriversinclude等几个目录,共200多条文件。

Vivi主要包括下面几个目录:

arch:此目录包括了所有vivi支持的目标板的子目录,例如s3c2410,s3c2440目录。
drivers:其中包括了引导内核需要的设备的驱动程序(MTD和串口)。MTD目录下分mapnandnor三个目录。
init:这个目录只有main.cversion.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中赋值

/******   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

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

#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,
 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<<12)|(7<<8)|(7<<4)|(0<<0) )
 str r2, [r1, #oNFCONF]
 ldr r2, [r1, #oNFCONF]

 ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
 str r2, [r1, #oNFCONT]
 ldr r2, [r1, #oNFCONT]

 ldr r2, =(0x6)                              @ RnB Clear
 str r2, [r1, #oNFSTAT]
 ldr r2, [r1, #oNFSTAT]
 
 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, #0x4
 beq 2b

 ldr r2, [r1, #oNFCONT]              @ Flash Memory Chip Disable
 orr r2, r2, #0x2                          逻辑或指令
 str r2, [r1, #oNFCONT]

 @ 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

 mov r1, #GPIO_CTL_BASE
 add r1, r1, #oGPIO_F
 mov r2, #0xe0
 str r2, [r1, #oGPIO_DAT]

 @ copy vivi to RAM
 ldr r0, =VIVI_RAM_BASE         @vivi拷贝的目标地址

                            @#define VIVI_RAM_BASE (DRAM_BASE + DRAM_SIZE - VIVI_RAM_SIZE)在smdk24xx.h中定义
 mov     r1, #0x0                       @vivi拷贝的源地址
 mov r2, #0x20000                   @vivi拷贝的长度,从NANDFlash0地址拷贝128kSDRAM指定处

 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.hvivi/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 修改后的配置保存在这个文件中,我们也可以载入一个自己的配置文件来进行编译。

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