分类: LINUX
2009-06-30 22:27:45
命令 |
功能 |
Load |
把二进制文件载入Flash或RAM |
Part |
操作MTD分区信息。显示、增加、删除、复位、保存MTD分区 |
Param |
设置参数 |
Boot |
启动系统 |
Flash |
管理Flash,如删除Flash的数据 |
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考虑不需要使用电源管理 @ All LED on
@ 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
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拷贝的长度,从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 修改后的配置保存在这个文件中,我们也可以载入一个自己的配置文件来进行编译。