?
1.1 源码剖析处理器首先跳到ROM的入口地址,设置状态字并创建一个哑堆栈(dummy stack) 。下面是PPC860的romInit示例:
/* internals */
FUNC_EXPORT(_romInit) /* start of system code */
FUNC_EXPORT(romInit) /* start of system code */
.globl FUNC(sdata) /* start of data */
.globl _sdata
#ifdef INCLUDE_QUICK_BOOT
/* lch 2005-3-25 13:24 Add these two functions to speed up booting */
.globl fillLongs
.globl copyLongs
#endif /*INCLUDE_QUICK_BOOT*/
/* externals */
.extern romStart /* system initialization routine */
_sdata:
FUNC_LABEL(sdata)
.asciz "start of data"
.balign 4
_WRS_TEXT_SEG_START
/******************************************************************************
*
* romInit - entry point for VxWorks in ROM
*
* romInit
* (
* int startType /@ only used by 2nd entry point @/
* )
*/
FUNC_BEGIN(_romInit)
FUNC_BEGIN(romInit)
bl cold /* jump to the cold boot initialization */
bl start /* jump to the warm boot initialization */
/* copyright notice appears at beginning of ROM (in TEXT segment) */
.ascii "Copyright 1984-2003 Wind River Systems, Inc."
.balign _PPC_TEXT_SEG_ALIGN
cold:
li r3, BOOT_COLD /* set cold boot as start type */
/*
* When the PowerPC 860 is powered on, the processor fletch the
* instructions located at the address 0x100. We need to jump
* from the address 0x100 to the Flash space.
*/
/* SYPCR - turn off the system protection stuff */
mfspr r4, IMMR /* read it back, to be sure */
rlwinm r4, r4, 0, 0, 15 /* only high 16 bits count */
lis r5, HIADJ(0xFFFFFF88) /* Disable watchdog */
addi r5, r5, LO(0xffffff88) /* Disable watchdog */
stw r5, SYPCR(0)(r4)
lis r4, HIADJ(start) /* load r4 with the address */
addi r4, r4, LO(start) /* of start */
lis r5, HIADJ(romInit) /* load r5 with the address */
addi r5, r5, LO(romInit) /* of romInit() */
lis r6, HIADJ(ROM_TEXT_ADRS) /* load r6 with the address */
addi r6, r6, LO(ROM_TEXT_ADRS) /* of ROM_TEXT_ADRS */
sub r4, r4, r5 /* */
add r4, r4, r6
mtspr LR, r4 /* save destination address*/
/* into LR register */
blr /* jump to flash mem address */
/*MPC860内部的CS0片选信号是默认的系统启动片选信号,已被连接到Flash的片选线上。上电时,内存控制器会忽略所有参与征选逻辑的地址线的高17位,CS0总是有效。这样,Flash总会被选中,CPU从Flash偏移0x100的地方取指令,此时CPU的4GB内存空间的每个128KB的块都被映射到Flash。*/
start:
xor r4, r4, r4 /* clear register R4 */
/* set the MSR register to a known state */
mtmsr r4 /* cleat the MSR register */
/* DER - clear the Debug Enable Register */
mtspr DER, r4
/* ICR - clear the Interrupt Cause Register */
mtspr ICR, r4
/* ICTRL - initialize the Intstruction Support Control register */
lis r5, HIADJ(0x00000007)
addi r5, r5, LO(0x00000007)
mtspr ICTRL, r5
/* disable the instruction/data cache */
lis r4, HIADJ ( CACHE_CMD_DISABLE) /* load disable cmd */
addi r4, r4, LO (CACHE_CMD_DISABLE)
mtspr IC_CST, r4 /* disable I cache */
mtspr DC_CST, r4 /* disable D cache */
/* unlock the instruction/data cache */
lis r4, HIADJ ( CACHE_CMD_UNLOCK_ALL) /* load unlock cmd */
addi r4, r4, LO (CACHE_CMD_UNLOCK_ALL)
mtspr IC_CST, r4 /* unlock all I cache lines */
mtspr DC_CST, r4 /* unlock all D cache lines */
/* invalidate the instruction/data cache */
lis r4, HIADJ (CACHE_CMD_INVALIDATE) /* load invalidate cmd*/
addi r4, r4, LO (CACHE_CMD_INVALIDATE)
mtspr IC_CST, r4 /* invalidate all I cache lines */
mtspr DC_CST, r4 /* invalidate all D cache lines */
/*
* initialize the IMMR register before any non-core registers
* modification.
*/
IMMR指示特殊设备和内部存储器映像的基地址,这是一个32位的寄存器,其中0~15bit为基地址的值(ISB),根据系统复位时配置字的值来定。
/* INTERNAL_MEM_MAP_ADDR =0x02b00000,defined in ads860.h. noted by dgs*/
lis r4, HIADJ( INTERNAL_MEM_MAP_ADDR)
addi r4, r4, LO(INTERNAL_MEM_MAP_ADDR)
mtspr IMMR, r4 /* initialize the IMMR register */
mfspr r4, IMMR /* read it back, to be sure */
rlwinm r4, r4, 0, 0, 15 /* only high 16 bits count */
/*XXXXX lch config Port C 6 to output high*/
xor r5, r5, r5
sth r5, PCPAR(0)(r4)
xor r5, r5, r5
sth r5, PCSO(0)(r4)
lis r5, HIADJ( PCDIR_VALUE)
addi r5, r5, LO(PCDIR_VALUE)
sth r5, PCDIR(0)(r4)
lis r5, HIADJ( PCDAT_VALUE)
addi r5, r5, LO(PCDAT_VALUE)
sth r5, PCDAT(0)(r4)
/*
* Map the bank 0 to the flash area - On the ADS board at reset time
* the bank 0 is already used to map the flash.
*/
/*上电时,由于只有一个片选信号有效,它选通了 Flash,而RAM和其它存储设备地址无效,需要经过地址空间重映射才能访问。MPC860的地址空间重映射是通过设置0R0~OR7、BR0~BR7 这十六个寄存器完成的。由于上电时4GB的地址空间均被Flash占用,所以0xFFF00100这个地址仍在Flash的偏移0x100处。在寄存器初始化过程中,需要把SDRAM、MPC860内部寄存器空间以及外设等也映射进来。在进行这些操作前,需要把Flash的位置固定下来,例如映射到 0xFE000000,这个操作是通过设置OR0和BR0寄存器实现的。但在写OR0时,CPU仍然在0xFFF00000的那一块取指令,而Flash 即将被映射到0xFE000000块,所以程序必定出现“跑飞”的现象,必须对程序计数器(PC)进行调整,然而PC指针对程序员是不可见的,必须用跳转指令修改它。在Flash地址映射完成后,通过设置OR1~OR7、BR1~BR7可以完成对所有存储器空间的映射,各种存储设备可映射在CPU地址空间 中的任意位置,但相互之间不能冲突。*/
基寄存器(BR0-BR7)包含了基地址和地址类型,以及存储器属性和处理存储器操作选择的模块(machine)。
/*CS0 : bootrom(sst39vf040,512k*8)
* Base - 0xFE000000
* Width - 8Bit
* Size - 0x80000 (512KB)
*/
lis r5, HIADJ( (ROM_BASE_ADRS & BR_BA_MSK) | BR_V | BR_PS_8)
addi r5, r5, LO((ROM_BASE_ADRS & BR_BA_MSK) | BR_V | BR_PS_8)
stw r5, BR0(0)(r4)
lis r5, HIADJ( 0xFFF80000 | OR_CSNT_SAM | OR_BI | OR_SCY_4_CLK )
addi r5, r5, LO( 0xFFF80000 | OR_CSNT_SAM | OR_BI | OR_SCY_4_CLK )
stw r5, OR0(0)(r4)
/* CS1 - FLASH */
lis r5, HIADJ (CS1_FLASH_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK| OR_ACS_DIV2)
addi r5, r5, LO (CS1_FLASH_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK | OR_ACS_DIV2)
stw r5, OR1(0)(r4)
lis r5, HIADJ (CS1_FLASH_BASE | BR_MS_GPCM | CS1_FLASH_WIDTH | BR_V)
addi r5, r5, LO (CS1_FLASH_BASE | BR_MS_GPCM | CS1_FLASH_WIDTH | BR_V)
stw r5, BR1(0)(r4)
/* CS2 - SDRAM */
/* CS3 */
lis r5, HIADJ (CS3_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_6_CLK | OR_ACS_DIV4)
addi r5, r5, LO (CS3_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_6_CLK |OR_ACS_DIV4)
stw r5, OR3(0)(r4)
lis r5, HIADJ (CS3_CHIP_BASE | BR_MS_GPCM | CS3_CHIP_WIDTH | BR_V)
addi r5, r5, LO (CS3_CHIP_BASE | BR_MS_GPCM | CS3_CHIP_WIDTH | BR_V)
stw r5, BR3(0)(r4)
/* CS4 */
lis r5, HIADJ (CS4_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_3_CLK | OR_ACS_DIV4 | OR_TRLX )
addi r5, r5, LO (CS4_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_3_CLK| OR_ACS_DIV4 |OR_TRLX)
stw r5, OR4(0)(r4)
lis r5, HIADJ (CS4_CHIP_BASE | BR_MS_GPCM | CS4_CHIP_WIDTH | BR_V)
addi r5, r5, LO (CS4_CHIP_BASE | BR_MS_GPCM | CS4_CHIP_WIDTH | BR_V)
stw r5, BR4(0)(r4)
/* CS5 */
lis r5, HIADJ (CS5_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK| OR_ACS_DIV2)
addi r5, r5, LO (CS5_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK| OR_ACS_DIV2)
stw r5, OR5(0)(r4)
lis r5, HIADJ (CS5_CHIP_BASE | BR_MS_GPCM | CS5_CHIP_WIDTH | BR_V)
addi r5, r5, LO (CS5_CHIP_BASE | BR_MS_GPCM | CS5_CHIP_WIDTH | BR_V)
stw r5, BR5(0)(r4)
/* CS6 */
lis r5, HIADJ (CS6_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK| OR_ACS_DIV2)
addi r5, r5, LO (CS6_CHIP_MASK | OR_CSNT_SAM | OR_BI | OR_SCY_15_CLK| OR_ACS_DIV2)
stw r5, OR6(0)(r4)
lis r5, HIADJ (CS6_CHIP_BASE | BR_MS_GPCM | CS6_CHIP_WIDTH | BR_V)
addi r5, r5, LO (CS6_CHIP_BASE | BR_MS_GPCM | CS6_CHIP_WIDTH | BR_V)
stw r5, BR6(0)(r4)
/* SYPCR - turn off the system protection stuff */
lis r5, HIADJ( SYPCR_SWTC | SYPCR_BMT | SYPCR_BME | SYPCR_SWF)
addi r5, r5, LO(SYPCR_SWTC | SYPCR_BMT | SYPCR_BME | SYPCR_SWF)
stw r5, SYPCR(0)(r4)
/* SPR 65678 - Lock the Key Registers (they protect the register
* values from corruption on power cycle. See MCG's EWT # 867 for
* the symptoms and outcome of corrupted registers.
*
* r4 holds the address of the IMMR
*
* xxK registers are locked by writing any value other than 0x55CCAA33
* to the register, or by reading the register. They are unlocked
* by writing 0x55CCAA33 to the register. After locking, any write
* access to the locked SIU register will cause a MCE. (in one case,
* not an MCE but a software emulation exception. See the MPC860
* user's manual, section 11 page 11 ff.)
*/
#ifdef USE_KEYED_REGS
/* pre-loading r7 with '~KEYED_REG_UNLOCK_VALUE' (ie, 'lock it')
* pre-loading r8 with ' KEYED_REG_UNLOCK_VALUE' (ie, 'unlock it')
***/
lis r7, HIADJ( ~KEYED_REG_UNLOCK_VALUE )
addi r7, r7, LO( ~KEYED_REG_UNLOCK_VALUE )
lis r8, HIADJ( KEYED_REG_UNLOCK_VALUE )
addi r8, r8, LO( KEYED_REG_UNLOCK_VALUE )
#else
/* pre-loading r7 with ' KEYED_REG_UNLOCK_VALUE' (ie, 'unlock it') */
lis r7, HIADJ( KEYED_REG_UNLOCK_VALUE )
addi r7, r7, LO( KEYED_REG_UNLOCK_VALUE )
#endif
stw r7, TBSCRK(0)(r4)
stw r7, TBREFF0K(0)(r4)
stw r7, TBREFF1K(0)(r4)
stw r7, TBK(0)(r4)
stw r7, RTCSCK(0)(r4)
stw r7, RTCK(0)(r4)
stw r7, RTSECK(0)(r4)
stw r7, RTCALK(0)(r4)
stw r7, PISCRK(0)(r4)
stw r7, PITCK(0)(r4)
stw r7, SCCRK(0)(r4)
stw r7, PLPRCRK(0)(r4)
stw r7, RSRK(0)(r4)
isync
/* TBSCR - initialize the Time Base Status and Control register */
#ifdef USE_KEYED_REGS
stw r8, TBSCRK(0)(r4) /* others are TBREFF0K, TBREFF1K and TBK */
isync
#endif
lis r5, HIADJ( TBSCR_REFA | TBSCR_REFB)
addi r5, r5, LO(TBSCR_REFA | TBSCR_REFB)
sth r5, TBSCR(0)(r4)
#ifdef USE_KEYED_REGS
stw r7, TBSCRK(0)(r4)
#endif
#ifdef USE_KEYED_REGS
stw r8, PISCRK(0)(r4) /* others are TBREFF0K, TBREFF1K and TBK */
isync
#endif
/* set PIT status and control init value */
li r5, PISCR_PS | PISCR_PITF
sth r5, PISCR(0)(r4)
#ifdef USE_KEYED_REGS
stw r7, PISCRK(0)(r4)
#endif
/* set the SPLL frequency */
lis r5, HIADJ(PLPRCR_VAL)
addi r5, r5, LO(PLPRCR_VAL)
#ifdef USE_KEYED_REGS
stw r8, PLPRCRK(0)(r4) /* others are TBREFF0K, TBREFF1K and TBK */
isync
#endif
/*
* For Errata MPC860 SIU9
* Delay to stop bus access while bus stablises after write to this register
* Set delay to the longest bus access possible for your setup
* Can cause reset if delay isn't long enough
* Note cache not enabled at this point
*/
nop
nop
isync
stw r5, PLPRCR(0)(r4)
isync
divw r5, r4, r4 /* waste time (r4 != 0) */
divw r5, r4, r5 /* 13 clocks */
nop
nop
isync
#ifdef USE_KEYED_REGS
stw r7, PLPRCRK(0)(r4)
#endif
/* SIUMCR */
/*modified by dgs for using irq4*/
lis r6, HIADJ(SIUMCR_FRC)
addi r6, r6, LO(SIUMCR_FRC)
lwz r5, SIUMCR(0)(r4)
or r5, r5, r6
stw r5, SIUMCR(0)(r4)
divw r5, r4, r4 /* waste time (r4 != 0) */
divw r5, r4, r5 /* 13 clocks */
nop
nop
isync
/*new add by dgs for compare with zl_bsp*/
lis r5, HIADJ (0xff800000) /* Clear memory status register */
addi r5, r5,LO (0xff800000)
stw r5, MSTAT(0)(r4)
/*new add end*/
/*
* we program the MPTPR with the largest allowed divider
* and the PTA value accordingly. So here we figure out the
* correct value for the PTA field.
*/
li r6, MPTPR_PTP_DIV64
lis r11, HIADJ ((REFRESH_VALUE / 64) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 64) << MAMR_PTA_SHIFT)
cmpwi r11,0
bne mptprInit
/* try with the divider by 32 */
li r6, MPTPR_PTP_DIV32
lis r11, HIADJ ((REFRESH_VALUE / 32) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 32) << MAMR_PTA_SHIFT)
cmpwi r11,0
bne mptprInit
/* try with the divider by 16 */
li r6, MPTPR_PTP_DIV16
lis r11, HIADJ ((REFRESH_VALUE / 16) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 16) << MAMR_PTA_SHIFT)
cmpwi r11,0
bne mptprInit
/* try with the divider by 8 */
li r6, MPTPR_PTP_DIV8
lis r11, HIADJ ((REFRESH_VALUE / 8) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 8) << MAMR_PTA_SHIFT)
cmpwi r11,0
bne mptprInit
/* try with the divider by 4 */
li r6, MPTPR_PTP_DIV4
lis r11, HIADJ ((REFRESH_VALUE / 4) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 4) << MAMR_PTA_SHIFT)
cmpwi r11,0
bne mptprInit
/* it has to be the divide by 2 */
li r6, MPTPR_PTP_DIV2
lis r11, HIADJ ((REFRESH_VALUE / 2) << MAMR_PTA_SHIFT)
addi r11, r11, LO ((REFRESH_VALUE / 2) << MAMR_PTA_SHIFT)
mptprInit:
/* program the MPTPR */
sth r6, MPTPR(0)(r4)
/*
* initialize MxMR but don't enable refresh until after
* SDRAM initialization.
*/
lis r6, HIADJ (MAMR_DEFAULT_VALUE)
addi r6, r6, LO (MAMR_DEFAULT_VALUE)
or r6, r6, r11
stw r6, MAMR(0)(r4)
/*del by dgs for compare with zl_bsp
lis r6, HIADJ (MBMR_DEFAULT_VALUE)
end del by dgs */
upmaInit: /* 初始化内存控制器(UPM) */
/*
* load r6/r7 with the start/end address of the UPM table for an
* SDRAM @ 50MHZ.
*/
lis r6, HIADJ( upmaTableSdram)
addi r6, r6, LO(upmaTableSdram)
lis r7, HIADJ( upmaTableSdramEnd)
addi r7, r7, LO(upmaTableSdramEnd)
/* init UPMA for memory access */
sub r5, r7, r6 /* compute table size */
srawi r5, r5, 2 /* in integer size */
/* convert UpmTable to ROM based addressing */
lis r7, HIADJ(romInit)
addi r7, r7, LO(romInit)
lis r8, HIADJ(ROM_TEXT_ADRS)
addi r8, r8, LO(ROM_TEXT_ADRS)
sub r6, r6, r7 /* subtract romInit base address */
add r6, r6, r8 /* add in ROM_TEXT_ADRS address */
lis r9, HIADJ (MCR_OP_WRITE | MCR_UM_UPMA | MCR_MB_CS0)
addi r9, r9, LO(MCR_OP_WRITE | MCR_UM_UPMA | MCR_MB_CS0)
UpmaWriteLoop:
/* write the UPM table in the UPM */
lwz r10, 0(r6) /* get data from table */
stw r10, MDR(0)(r4) /* store the data to MD register */
stw r9, MCR(0)(r4) /* issue command to MCR register */
addi r6, r6, 4 /* next entry in the table */
addi r9, r9, 1 /* next MAD address */
addi r5,r5,-1
cmpwi r5,0
bne UpmaWriteLoop
/*
* Configure the 32 bit address to be output on the address bus
* if AMX = 0xb11.
* See section 16.6.4.1 "RAM Words". The following values must
* be placed on the defined SDRAM address pins:
* A[9] = 0 burst write mode
* A[6:4] = 010 cas latency of two
* A[3] = 0 sequential mode
* A[2:0] = 010 burst length 4
*
* The address must be shifted left by 2 bits for 32 bit wide SDRAM...
* (0b0100010 << 2) = 0x88
*/
lis r5, HIADJ(LOCAL_MEM_LOCAL_ADRS | 0x88)
addi r5, r5, LO(LOCAL_MEM_LOCAL_ADRS | 0x88)
stw r5, MAR(0)(r4)
/*
* Issue precharge command (PRCG) and wait the precharge time (t-rp).
* Run precharge pattern from UPMB location 5.
*/
lis r5, HIADJ(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_1X | 0x5)
addi r5, r5, LO(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_1X | 0x5)
stw r5, MCR(0)(r4)
/* run refresh pattern 8 times */
lis r5, HIADJ(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_8X | 0x30)
addi r5, r5, LO(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_8X | 0x30)
stw r5, MCR(0)(r4)
/*
* issue a mode register set (MRS) to initialize the SDRAM mode
* register. This programs the burst length, CAS latency and
* write mode. Run MRS pattern from UPMB location 6.
*/
lis r5, HIADJ(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_1X | 0x6)
addi r5, r5, LO(MCR_OP_RUN | MCR_UM_UPMA | MCR_MB_CS2 | \
MCR_MCLF_1X | 0x6)
stw r5, MCR(0)(r4)
/* program OR2 and BR2 for 64/32 Mbytes SDRAM Memory Array */
lis r5, HIADJ ((~(SDRAM_SIZE - 1)) | OR_CSNT_SAM)
addi r5, r5, LO ((~(SDRAM_SIZE - 1)) | OR_CSNT_SAM)
stw r5, OR2(0)(r4) /* set OR2 to the previously computed value */
lis r5, HIADJ ((LOCAL_MEM_LOCAL_ADRS & BR_BA_MSK) | BR_MS_UPMA \
| BR_V)
addi r5, r5, LO ((LOCAL_MEM_LOCAL_ADRS & BR_BA_MSK) | BR_MS_UPMA \
| BR_V)
stw r5, BR2(0)(r4)
/* enable SDRAM refresh cycles */
lis r5, HIADJ (MAMR_DEFAULT_VALUE | MAMR_PTAE)
addi r5, r5,LO (MAMR_DEFAULT_VALUE | MAMR_PTAE)
add r5, r5, r11
stw r5, MAMR(0)(r4)
/* initialize the stack pointer */
lis sp, HIADJ(STACK_ADRS)
addi sp, sp, LO(STACK_ADRS)
/* initialize r2 and r13 according to EABI standard */
#if FALSE /* SDA Not supported yet */
lis r2, HIADJ(_SDA2_BASE_)
addi r2, r2, LO(_SDA2_BASE_)
lis r13, HIADJ(_SDA_BASE_)
addi r13, r13, LO(_SDA_BASE_)
#endif
/* go to C entry point */
addi sp, sp, -FRAMEBASESZ /* get frame stack */
/*
* calculate C entry point: routine - entry point + ROM base
* routine = romStart
* entry point = romInit = R7
* ROM base = ROM_TEXT_ADRS = R8
* C entry point: romStart - R7 + R8
*/
lis r6, HIADJ(romStart)
addi r6, r6, LO(romStart) /* load R6 with C entry point */
sub r6, r6, r7 /* routine - entry point */
add r6, r6, r8 /* + ROM base */
mtlr r6 /* move C entry point to LR */
blr /* jump to the C entry point */
FUNC_END(_romInit)
FUNC_END(romInit)
/* This 50 MHz SDRAM table is for...
* 860EN Rev B.1 9829 and newer silicon
* 860T Rev B.3 9832 and newer silicon
*
* This table will NOT work with older 860EN or 860T parts.
*/
upmaTableSdram:
/* single read (offset 0x00 in upm ram) */
.long 0x1F0DFC04, 0xEEAFBC04, 0x11AF7C04, 0xEFBEEC00
.long 0x1FFDDC47, 0x1FFDDF35, 0xEFEEAF34, 0x1FBD5F35
/* burst read (offset 0x08 in upm ram) */
.long 0x1F0DFC04, 0xEEAFBC04, 0x10AF7C04, 0xF0AFFC00
.long 0xF0AFFC00, 0xF1AFFC00, 0xEFBEEC00, 0x1FFDDC47
.long 0x00FFF000, 0x11FFF447, 0xFFFFFC47, 0xFFFFFC04
.long 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0x1F2DFC04
/* single write (offset 0x18 in upm ram) */
.long 0x1F2DFC04, 0xEEAFAC00, 0x01BE4C04, 0x1FFDDC47
.long 0x00AF0004, 0x1FFDD447, 0xFFFFFC44, 0x1F0DFC04
/* burst write (offset 0x20 in upm ram) */
.long 0x1F0DFC04, 0xEEAFAC00, 0x10AF5C00, 0xF0AFFC00
.long 0xF0AFFC00, 0xE1BEEC04, 0x1FFDDC47, 0x00FFF004
.long 0x11FFF447, 0xFFFFFC47, 0xFFFFFC04, 0xFFFFFC04
.long 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0x1FFD7C84
/* refresh (offset 0x30 in upm ram) */
.long 0x1FFD7C84, 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04
.long 0xFFFFFC84, 0xFFFFFC07, 0xFFFFFC04, 0xFFFFFC04
.long 0xFFFFFC04, 0xFFFFFC04, 0xFFFFFC04, 0x7FFFFC07
/* exception (offset 0x3C in upm ram) */
.long 0x7FFFFC07, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
upmaTableSdramEnd:
#ifdef INCLUDE_QUICK_BOOT
/* lch 2005-3-25 13:24 Add these two functions to speed up booting */
/*******************************************************************************
*
* fillLongs - fill a buffer with a value a long at a time
*
* This routine fills the first <nlongs> longs of the buffer with
*
* LOCAL void fillLongs (buf, nlongs, val)
* UINT *buf; pointer to buffer
* UINT nlongs; number of longs to fill
* UINT val; char with which to fill buffer
*/
fillLongs:
cmpwi r4, 0
beqlr
mtctr r4
subi r3, r3, 4
flsCont:
stwu r5, 4(r3)
bdnz flsCont
blr
/*******************************************************************************
*
* copyLongs - copy one buffer to another a long at a time
*
* This routine copies the first
*
* LOCAL void copyLongs (source, destination, nlongs)
* UINT *source; pointer to source buffer
* UINT *destination; pointer to destination buffer
* UINT nlongs; number of longs to copy
*/
copyLongs:
cmpwi r5, 0
beqlr
cmpw r3, r4
beqlr
li r6, 0
bgt sourceGreat
slwi r11, r5, 2
add r3, r3, r11
add r4, r4, r11
b sourceLess
sourceGreat:
subi r3, r3, 4
subi r4, r4, 4
mtctr r5
sourceGreatCont:
lwzu r7, 4(r3)
stwu r7, 4(r4)
bdnz sourceGreatCont
mr. r5, r6
beqlr
sourceLess:
mtctr r5
sourceLessCont:
lwzu r7, -4(r3)
stwu r7, -4(r4)
bdnz sourceLessCont
mr. r5, r6
beqlr
#endif /*INCLUDE_QUICK_BOOT*/
上述程序中romInit()函数做的工作有:
? 将相关寄存器清零和置位;
? 屏蔽中断;
? 关闭数据、指令Cache;
? 初始化内存:对SDRAM接口各寄存器进行配置;
? 初始化堆栈指针;
? 计算romStart()函数地址,然后跳转到该函数执行C语言代码,并不再返回。
romInit()函数应该以浮动代码代码的形式存在。浮动代码(Position Independent Code,位置无关代码,简称PIC)使用的转移指令都是相对于当前程序计数器(PC)的偏移量;代码中引用变量、函数的地址都是相对于某个基地址的偏移量。总之,从不引用一个绝对地址,这样,无论程序被加载到什么地址空间,不用修补代码就可以正常工作。
跳到C程序的入口地址romStart后,该函数根据哑堆栈中的参数决定是否清零内存RAM(若是冷启动则清零),再把ROM段的剩余部分拷贝到RAM,拷贝的过程如下:
(1)代码段不是驻留在ROM中,要拷贝代码段和数据段;
(2)如代码段是驻留在ROM中,则只拷贝数据段;
(3)未用的内存清零;
(4)如果ROM代码是压缩的,要进行解压缩。
下面是从romStart()函数中提取的骨干:
/* bootInit.c - ROM initialization module */
void romStart(FAST int startType /* start type */)
{
volatile FUNCPTR absEntry;
/* 从ROM复制到RAM */
#ifdef ROM_RESIDENT
/* ROM驻留的VxWorks,只COPY数据段 */
copyLongs((UINT*)etext, (UINT*)RESIDENT_DATA, ((UINT)wrs_kernel_data_end -
(UINT)RESIDENT_DATA) / sizeof(long));
#else /* RAM中运行 */
#ifdef UNCOMPRESS /*未压缩的,复制TEXT、DATA段*/
((FUNCPTR)ROM_OFFSET(copyLongs))(ROM_TEXT_ADRS, (UINT)romInit,
ROM_COPY_SIZE / sizeof(long));
#else /*压缩的,复制非压缩型区域*/
((FUNCPTR)ROM_OFFSET(copyLongs))(ROM_TEXT_ADRS, (UINT)romInit,
((UINT) binArrayStart - (UINT)romInit) / sizeof(long));
((FUNCPTR)ROM_OFFSET(copyLongs))((UINT*)((UINT)ROM_TEXT_ADRS +
((UINT)BINARRAYEND_ROUNDOFF - (UINT)romInit)),
(UINT*)BINARRAYEND_ROUNDOFF,
( (UINT)wrs_kernel_data_end - (UINT)binArrayEnd) / sizeof(long));
#endif /* UNCOMPRESS */
#endif /* ROM_RESIDENT */
/* 清内存 */
#if (!defined (BOOTCODE_IN_RAM))
/* 冷启动,清楚所有内存 */
if (startType &BOOT_CLEAR)
{
#ifdef ROM_RESIDENT
fillLongs((UINT*)SYS_MEM_BOTTOM, ((UINT)RESIDENT_DATA - STACK_SAVE -
(UINT)SYS_MEM_BOTTOM) / sizeof(long), 0);
fillLongs(((UINT*)wrs_kernel_data_end), ((UINT)SYS_MEM_TOP - ((UINT)
wrs_kernel_data_end)) / sizeof(long), 0);
#else /* ROM_RESIDENT */
fillLongs((UINT*)(SYS_MEM_BOTTOM), ((UINT)romInit - STACK_SAVE –
(UINT)SYS_MEM_BOTTOM) / sizeof(long), 0);
#if defined (UNCOMPRESS)
fillLongs((UINT*)((UINT)romInit + ROM_COPY_SIZE),
((UINT)SYS_MEM_TOP
- ((UINT)romInit + ROM_COPY_SIZE)) / sizeof(long), 0);
#else
fillLongs((UINT*)wrs_kernel_data_end, ((UINT)SYS_MEM_TOP - (UINT)
wrs_kernel_data_end) / sizeof(long), 0);
#endif /* UNCOMPRESS */
#endif /* ROM_RESIDENT */
/* 确保启动行为空 */
*(BOOT_LINE_ADRS) = EOS;
}
#endif
/* 跳到usrInit()*/
#if defined (UNCOMPRESS) || defined (ROM_RESIDENT)
absEntry = (FUNCPTR)usrInit; /* on to bootConfig */
#else
{
/* 解压缩到RAM_DST_ADRS */
if (UNCMP_RTN((UCHAR*)ROM_OFFSET(binArrayStart),
(UCHAR*)RAM_DST_ADRS, binArrayEnd - binArrayStart) != OK)
return ; /* if we return then ROM's will halt */
absEntry = (FUNCPTR)RAM_DST_ADRS; /* RAM入口点 */
}
#endif /* defined UNCOMPRESS || defined ROM_RESIDENT */
(absEntry)(startType);
}
romStart()函数会调用预内核的通用初始化函数usrInit(),位于usrConfig.C或bootConfig.C中。romStart关中断,存储有关启动类型(boot type)的信息,在VxWorks内核运行前进行必要的初始化。
(1)初始化cache模式,设置为安全状态,在usrInit()结束时使cache有效;
(2)清零系统bss段;
(3)初始化中断向量表,调用VectBaseSet(),exeVecInit();
(4)初始化系统硬件,但使之进入“Quiescent”状态,调用sysHwInit(),这是一个与硬件有关的过程,是我们要针对不同的目标板进行修改的重要部分,其中涉及到串口,网口的初始化,CONSOLE的配置等;
(5)调用usrKernelInit(),并使能cache;
(6)调用kernelInit(),创建usrRoot()。
usrConfig.C中的usrInit()和bootConfig.C中的相似。bootConfig.C中的usrInit()流程如下:
void usrInit(int startType)
{
while (trapValue1 != TRAP_VALUE_1 || trapValue2 != TRAP_VALUE_2)
{
/* infinite loop */;
}
#ifdef INCLUDE_SYS_HW_INIT_0
SYS_HW_INIT_0();
#endif /* INCLUDE_SYS_HW_INIT_0 */
/* configure data and instruction cache if available and leave disabled */
#ifdef INCLUDE_CACHE_SUPPORT
/*
* SPR 73609: If a cache is not to be enabled, don't require
* its mode to be defined. Instead, default it to disabled.
*/
#if (!defined(USER_D_CACHE_ENABLE) && !defined(USER_D_CACHE_MODE))
#define USER_D_CACHE_MODE CACHE_DISABLED
#endif /* !USER_D_CACHE_ENABLE && !USER_D_CACHE_MODE */
#if (!defined(USER_I_CACHE_ENABLE) && !defined(USER_I_CACHE_MODE))
#define USER_I_CACHE_MODE CACHE_DISABLED
#endif /* !USER_I_CACHE_ENABLE && !USER_I_CACHE_MODE */
cacheLibInit(USER_I_CACHE_MODE, USER_D_CACHE_MODE);
#endif /* INCLUDE_CACHE_SUPPORT */
/* don't assume bss variables are zero before this call */
bzero(edata, end - edata); /* zero out bss variables */
sysStartType = startType;
intVecBaseSet((FUNCPTR*)VEC_BASE_ADRS); /* set vector base table */
excVecInit(); /* install exception vectors */
sysHwInit(); /* initialize system hardware */
usrKernelInit(); /* configure the Wind kernel */
#ifdef INCLUDE_CACHE_SUPPORT
#ifdef USER_I_CACHE_ENABLE
cacheEnable(INSTRUCTION_CACHE); /* enable instruction cache */
#endif /* USER_I_CACHE_ENABLE */
#endif /* INCLUDE_CACHE_SUPPORT */
/* start the kernel specifying usrRoot as the root task */
kernelInit((FUNCPTR)usrRoot, ROOT_STACK_SIZE,
(char*)MEM_POOL_START_ADRS,
sysMemTop(), ISR_STACK_SIZE, INT_LOCK_LEVEL);
}
sysHwInit()定义于syslib.c中,大部分硬件初始化工作都在这部分完成。系统可将包括串口、网口等硬件设备的初始化入口程序添加到该函数中,相关设备的驱动程序可作为子文件引入syslib.c。
usrKernelInit()初始化多任务环境,依次调用classLibInit(),taskLibInit(),taskHookInit(),semBLibInit(),semMLibInit(),semCLibInit(),semOLibInit(),wbLibInit(),msgQLibInit(),qInit(),workQInit()。
kernelInit()初始化内核可选组建(kernel facility)并启动根任务。函数功能:
(1)激活intLockLevelSet()
(2)从内存池顶部创建堆栈和TCB
(3)调用taskInit(),taskActivate(),用于usrRoot()
(4)调用usrRoot()
usrRoot初始化I/O系统、驱动器、设备(在configAll.h和config.h中指定),并启动其它任务。bootConfig.C中的usrRoot()流程如下:
/* 初始化和启动boot command loop task */
void usrRoot(char *pMemPoolStart, /* start of system memory partition */
unsigned memPoolSize /* initial size of mem pool */)
{
char tyName[20];
int ix;
#ifdef INCLUDE_END
int count;
END_TBL_ENTRY *pDevTbl;
#endif /* INCLUDE_END */
/* 初始化内存池 */
memInit(pMemPoolStart, memPoolSize); /* XXX select between memPartLibInit */
/* 设置系统定时器 */
sysClkConnect((FUNCPTR)usrClock, 0); /* connect clock interrupt routine */
sysClkRateSet(SYS_CLK_RATE); /* set system clock rate */
sysClkEnable(); /* start it */
/* select library需要在tyLib模块前初始化 */
#ifdef INCLUDE_SELECT
selectInit(NUM_FILES);
#endif /* INCLUDE_SELECT */
/* 初始化I/O和文件系统 */
iosInit(NUM_DRIVERS, NUM_FILES, "/null");
consoleFd = NONE;
/* 给板上设备安装驱动 */
#ifdef INCLUDE_TYCODRV_5_2
#ifdef INCLUDE_TTY_DEV
if (NUM_TTY > 0)
{
tyCoDrv(); /* install console driver */
for (ix = 0; ix < NUM_TTY; ix++)
/* create serial devices */
{
sprintf(tyName, "%s%d", "/tyCo/", ix);
(void)tyCoDevCreate(tyName, ix, 512, 512);
if (ix == CONSOLE_TTY)
strcpy(consoleName, tyName);
/* store console name */
}
consoleFd = open(consoleName, O_RDWR, 0);
/* set baud rate */
(void)ioctl(consoleFd, FIOBAUDRATE, CONSOLE_BAUD_RATE);
(void)ioctl(consoleFd, FIOSETOPTIONS, OPT_ECHO | OPT_CRMOD |
OPT_TANDEM | OPT_7_BIT);
}
#endif /* INCLUDE_TTY_DEV */
#else /* !INCLUDE_TYCODRV_5_2 */
#ifdef INCLUDE_TTY_DEV
if (NUM_TTY > 0)
{
ttyDrv(); /* install console driver */
for (ix = 0; ix < NUM_TTY; ix++)
/* create serial devices */
{
#if (defined(INCLUDE_WDB) && (WDB_COMM_TYPE ==
WDB_COMM_SERIAL))
if (ix == WDB_TTY_CHANNEL)
/* don't use WDBs channel */
continue;
#endif
sprintf(tyName, "%s%d", "/tyCo/", ix);
(void)ttyDevCreate(tyName, sysSerialChanGet(ix), 512, 512);
if (ix == CONSOLE_TTY)
/* init the tty console */
{
strcpy(consoleName, tyName);
consoleFd = open(consoleName, O_RDWR, 0);
(void)ioctl(consoleFd, FIOBAUDRATE, CONSOLE_BAUD_RATE);
(void)ioctl(consoleFd, FIOSETOPTIONS, OPT_ECHO | OPT_CRMOD |
OPT_TANDEM | OPT_7_BIT);
}
}
}
#endif /* INCLUDE_TTY_DEV */
#ifdef INCLUDE_PC_CONSOLE
pcConDrv();
for (ix = 0; ix < N_VIRTUAL_CONSOLES; ix++)
{
sprintf(tyName, "%s%d", "/pcConsole/", ix);
(void)pcConDevCreate(tyName, ix, 512, 512);
if (ix == PC_CONSOLE)
/* init the console device */
{
strcpy(consoleName, tyName);
consoleFd = open(consoleName, O_RDWR, 0);
(void)ioctl(consoleFd, FIOBAUDRATE, CONSOLE_BAUD_RATE);
(void)ioctl(consoleFd, FIOSETOPTIONS, OPT_ECHO | OPT_CRMOD |
OPT_TANDEM | OPT_7_BIT);
}
}
#endif /* INCLUDE_PC_CONSOLE */
#endif /* !INCLUDE_TYCODRV_5_2 */
#ifdef INCLUDE_WDB
wdbConfig(); /* configure and initialize the WDB agent */
vxBootFile[0] = NULL; /* clear boot line set by wdbConfig() */
#if defined(INCLUDE_TSFS_BOOT) &&
defined(INCLUDE_TSFS_BOOT_VIO_CONSOLE)
consoleFd = open("/vio/0", O_RDWR, 0); /* for Target Server Console */
#endif
#endif /* INCLUDE_WDB */
ioGlobalStdSet(STD_IN, consoleFd);
ioGlobalStdSet(STD_OUT, consoleFd);
ioGlobalStdSet(STD_ERR, consoleFd);
pipeDrv(); /* install pipe driver */
#if defined(INCLUDE_EXC_HANDLING) && defined(INCLUDE_EXC_TASK)
#ifdef INCLUDE_EXC_SHOW
excShowInit(); /* init exception show routines */
#endif
excInit(); /* initialize exception handling */
#endif /* defined(INCLUDE_EXC_HANDLING) && defined(INCLUDE_EXC_TASK) */
excHookAdd((FUNCPTR)bootExcHandler); /* install exc handler */
logInit(consoleFd, 5); /* initialize logging */
#ifdef INCLUDE_DOSFS
hashLibInit(); /* hashLib used by dosFS */
#endif
/* initialize object module loader */
#if defined(INCLUDE_AOUT)
bootAoutInit(); /* use a.out format */
#else /* coff or ecoff */
#if defined(INCLUDE_ECOFF)
bootEcoffInit(); /* use ecoff format */
#else /* coff */
#if defined(INCLUDE_COFF)
bootCoffInit(); /* use coff format */
#else /* coff */
#if defined(INCLUDE_ELF)
bootElfInit(); /* use elf format */
#endif
#endif /* mips cpp no elif */
#endif
#endif
#ifdef INCLUDE_PCMCIA
pcmciaInit(); /* init PCMCIA Lib */
#endif /* INCLUDE_PCMCIA */
#ifdef INCLUDE_END
/* initialize the MUX */
muxMaxBinds = MUX_MAX_BINDS;
if (muxLibInit() == ERROR)
return ;
/* can't return ERROR */
/* Initialize all the available devices. */
for (count = 0, pDevTbl = endDevTbl; pDevTbl->endLoadFunc != END_TBL_END;
pDevTbl++, count++)
{
cookieTbl[count].pCookie = muxDevLoad(pDevTbl->unit, pDevTbl->endLoadFunc,
pDevTbl->endLoadString, pDevTbl->endLoan, pDevTbl->pBSP);
if (cookieTbl[count].pCookie == NULL)
{
printf("muxLoad failed!\n");
}
cookieTbl[count].unitNo = pDevTbl->unit;
bzero((void*)cookieTbl[count].devName, END_NAME_MAX);
pDevTbl->endLoadFunc((char*)cookieTbl[count].devName, NULL);
}
#endif /* INCLUDE_END */
taskSpawn("tBoot", bootCmdTaskPriority, bootCmdTaskOptions,
bootCmdTaskStackSize, (FUNCPTR)bootCmdLoop, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
最后启动的“tBoot”任务,对应bootCmdLoop()函数的作用是:读取和执行用户的控制命令直到启动。VxWorks的引导最终通过bootLoad()函数完成:
LOCAL STATUS bootLoad(char *bootString, FUNCPTR *pEntry)
{
BOOT_PARAMS params;
/* copy bootString to low mem address, if specified */
if ((bootString != NULL) && (*bootString != EOS))
strcpy(BOOT_LINE_ADRS, bootString);
/* interpret boot command */
if (usrBootLineCrack(BOOT_LINE_ADRS, ¶ms) != OK)
return (ERROR);
/* Display boot parameters */
bootParamsShow(BOOT_LINE_ADRS);
/* set our processor number: may establish vme access, etc. */
sysFlags = params.flags;
sysProcNumSet(params.procNum);
#ifdef INCLUDE_SCSI_BOOT
if (strncmp(params.bootDev, "scsi", 4) == 0){…}
#endif /* INCLUDE_SCSI_BOOT */
#ifdef INCLUDE_FD
if (strncmp(params.bootDev, "fd", 2) == 0){…}
#endif /* INCLUDE_FD */
#ifdef INCLUDE_IDE
if (strncmp(params.bootDev, "ide", 3) == 0){…}
#endif /* INCLUDE_IDE */
#ifdef INCLUDE_ATA
if (strncmp(params.bootDev, "ata", 3) == 0){…}
#endif /* INCLUDE_ATA */
#ifndef INCLUDE_NETWORK
printf("\nError loading file: networking code not present.\n");
return (ERROR);
#else /* INCLUDE_NETWORK */
/* start the network */
/* initialize the generic socket library */
if (sockLibInit(NUM_FILES) == ERROR)
return (ERROR);
//...
#endif
}
跳到VxWorks入口点则是通过go()函数:
LOCAL void go(FUNCPTR entry)
{
printf("Starting at 0x%x...\n\n", (int)entry);
taskDelay(sysClkRateGet()); /* give the network a moment to close */
#ifdef INCLUDE_NETWORK
ifreset(); /* reset network to avoid interrupts */
#ifdef INCLUDE_END
/* Stop all ENDs to restore to known state for interrupts and DMA */
(void)muxDevStopAll(0);
#endif /* INCLUDE_END */
#endif /* INCLUDE_NETWORK */
#if (CPU_FAMILY == PPC)
cacheTextUpdate((void*)(LOCAL_MEM_LOCAL_ADRS), /* cache coherency */
(size_t)(sysMemTop() - LOCAL_MEM_LOCAL_ADRS));
#else
#ifdef INCLUDE_CACHE_SUPPORT
cacheClear(DATA_CACHE, NULL, ENTIRE_CACHE); /* push cache to mem */
#endif /* INCLUDE_CACHE_SUPPORT */
#endif /* (CPU_FAMILY == PPC) */
#if (CPU_FAMILY == I80X86)
sysClkDisable(); /* disable the system clock interrupt */
sysIntLock(); /* lock the used/owned interrupts */
#if defined (SYMMETRIC_IO_MODE) || defined (VIRTUAL_WIRE_MODE)
{
extern void loApicEnable();
loApicEnable(FALSE); /* disable the LOAPIC */
}
#if defined (SYMMETRIC_IO_MODE)
{
extern BOOL sysBp; /* TRUE for BP, FALSE for AP */
extern void ioApicEnable();
if (sysBp)
ioApicEnable(FALSE);
/* disable the IO APIC */
}
#endif /* (SYMMETRIC_IO_MODE) */
#endif /* (SYMMETRIC_IO_MODE) || (VIRTUAL_WIRE_MODE) */
#endif /* (CPU_FAMILY == I80X86) */
/* Lock interrupts before jumping out of boot image. The interrupts
* enabled during system initialization in sysHwInit()
*/
intLock();
(entry)(); /* go to entry point - never to return */
}
usrConfig.C中的usrRoot()流程和上面基本类似,不同于上述程序仅仅初始化必要的硬件和软件模块,usrConfig.C中的usrRoot()要初始化的东西非常多,所以代码量大,而且最终进入的是应用程序:
#ifdef INCLUDE_USER_APPL
/* Startup the user's application */
USER_APPL_INIT; /* must be a valid C statement or block */
#endif
Loadable的VxWork映像入口点为sysInit:
FUNC_LABEL(sysInit)
FUNC_BEGIN(_sysInit)
/*
* disable external interrupts and Instruction/Data MMU, set
* the exception prefix
*/
mfmsr p0 /* p0 = msr */
INT_MASK(p0, p1) /* mask EE bit */
rlwinm p1, p1, 0, _PPC_MSR_BIT_DR + 1, _PPC_MSR_BIT_IR - 1
rlwinm p1, p1, 0, _PPC_MSR_BIT_IP + 1, _PPC_MSR_BIT_IP - 1
mtmsr p1 /* msr = p1 */
isync /* ISYNC */
/* disable instruction and data caches */
lis p1, HIADJ ( CACHE_CMD_DISABLE) /* load disable cmd */
addi p1, p1, LO (CACHE_CMD_DISABLE)
mtspr IC_CST, p1 /* Disable I cache */
mtspr DC_CST, p1 /* Disable D cache */
/* unlock instruction and data caches */
lis p1, HIADJ ( CACHE_CMD_UNLOCK_ALL) /* load unlock cmd */
addi p1, p1, LO (CACHE_CMD_UNLOCK_ALL)
mtspr IC_CST, p1 /* Unlock I cache */
mtspr DC_CST, p1 /* Unlock D cache */
/* invalidate instruction and data caches */
lis p1, HIADJ ( CACHE_CMD_INVALIDATE) /* load invalidate cmd*/
addi p1, p1, LO (CACHE_CMD_INVALIDATE)
mtspr IC_CST, p1 /* Invalidate I cache */
mtspr DC_CST, p1 /* Invalidate D cache */
/* invalidate entries within both TLBs */
tlbia
/* initialize the stack pointer */
lis sp, HIADJ( RAM_LOW_ADRS)
addi sp, sp, LO(RAM_LOW_ADRS)
/* set the default boot code */
lis r3, HIADJ( BOOT_WARM_AUTOBOOT)
addi r3, r3, LO(BOOT_WARM_AUTOBOOT)
/* jump to usrInit */
addi sp, sp, -FRAMEBASESZ /* get frame stack */
b usrInit /* never returns - starts up kernel */
FUNC_END(_sysInit)
1.2 修改配置configAll.h
缺省定义了所有VxWorks的设置,如果不用缺省的设置,可在BSP目录下的config.h文件中用#define或#undef方式来更改设置;
config.h
config.h 文件包括了所有的特定CPU板的包含文件和定义。config.h 文件内容的标准组织如下:
(1)BSP 版本和修订 ID 号码;
(2)configAll.h (#included);
(3)内存cache 和MMU 配置;
(4)共享内存网络定义;
(5)片上内存的地址和大小;
(6)ROM 地址和大小;
(7)NVRAM 参数;
(8)缺省启动行(bootline)参数;
关于加载VxWorks影像文件,在启动行(boot line)设置可以从硬盘,软盘,网络,串口,ppp等等。示例:
硬盘
"ata=0,0(0,0)host:/ata0/vxWorks h=90.0.0.3 e=90.0.0.50 u=target"
软盘
"fd=0,0(0,0)host:/fd0/vxWorks h=90.0.0.3 e=90.0.0.50 u=target"
网络
"fei=0,0(0,0)host:/fei00/vxWorks h=90.0.0.3 e=90.0.0.50 u=target"
从ATA启动的解释如下:
bootline : ata=1,0(0,0)host:/ata1/vxWorks
| |
| |__drive(master or slave)
|
|__controller(0 refers to ata controller 0,1 refers to ata controller 1)
下面看boot line结构:
bootDev(unitNum,procNum) hostname:bootFile e=ead b=bad h=had g=gad u=username pw=password f=flags tn=targetName s=startupScript o=other
bootDev // 设备名,软盘:fd; 硬盘:ATA;网络要根据网卡的类型来做:NE2000及其兼容网卡为ENE,3COM以太网卡为ELT,Intel网卡为EEX,Intel82559网卡为fei ,3C905B PCI网卡为elPci。
unitNum / 设备单元号,一般指为0
procnum / cpu的处理器号,一般为0
flags / 标识,十六进制数,意义如下:
0x01: 关闭对处理器0的系统控制
0x02: 将局部symbols和全局symbols装入目标机symbols表
0x04: 禁止自动启动(即由用户输入boot line)
0x08: 快速boot(不计数等待用户输入)
0x40: 使用BOOTP or DHCP client
0x80: 使用TFTP获取image,否则使用RSH或FTP,用FTP时pw不为空
0x100: 使目标机登记为一个代理ARP client
ead / 目标机ip地址,此值如为空,网络接口不被帮定
bad / 背板接口
had / 主机ip地址
gad / 网关地址,如果主机和目标机不在一个局域网里,需要
bootFile: / 存放VxWorks image的路径
usr: / 使用FTP或RSH时的用户名
passwd: / ftp password
other: / 从网络启动时此值可为空,当从软盘或硬盘启动时,如果此值为你的网络
设备,boot会为你绑定网络设备
hostname: / 主机名,任意
targetName:/目标机名
startupScript: / 脚本名,在boot以后的target shell里执行
在boot line中,e,b,h等等参数都不要求次序,你也可以让它为空值,如”pw= ”就是指口令为空参数,看一个例子:
ene(0,0) raisecom:c:/tornado/target/config/pc486/VxWorks e="10".132.3.40 h="10".132.3.37 u="x86" pw="apue" tn="rod"
在上例中,网卡为NE2000及兼容网卡,主机名为raisecom,VxWorks image存放在c:\tornado\target\config\pc486这个目录下,目标机的网络地址为10.132.3.40,主机的网络地址为10.132.3.37,通过FTP服务器下载,用户名为x86,口令为apue,目标机名为rod
再看一个例子:
fd="0",0(0,0) lijun:/fd0/vxWorks e="10".132.3.40 h="10".132.3.37 u="x86" o="ene"
这个例子里面,用的是软盘启动VxWorks,在软盘做好boot后,还需要把VxWorks image拷入软盘,在boot 起来以后,引导程序会在软盘里寻找VxWorks,并把它启动。
软盘用fd0表示,硬盘用ATA(0,0),最后的参数o="ene" 表示网络设备是NE2000网卡,并将之和ip地址绑定。
(9)时间戳驱动支持;
(10)外部总线地址映射;
(11)网络设备和中断向量;
(12)bspname.h 文件 (#included)。
bspname.h
根据具体目标板设置串行接口、时钟以及I/O设备等。在该文件中必须包含以下内容:
(1)中断向量/级别;
(2)I/O设备地址;
(3)设备寄存器位的含义;
(4)系统和附加时钟参数(最大和最小速率)。
configNet.h
网络设备描述、配置。以下是网络设备描述的一个例子,在系统中应该添加类似的描述到configNet.h 文件中。
#define MOT_FCC_LOAD_FUNC sysMotFccEndLoad
#define MOT_FCC_LOAD_STRING ""
IMPORT END_OBJ* MOT_FCC_LOAD_FUNC (char *, void*);
在每一个网络设备的配置中,应该定义以上两个常量,以下对着两个常量进行说明:
LOAD_FUNC:
规定驱动endLoad()函数的入口点。例如,如果驱动的endLoad()入口点是sysMotFccEndLoad(),那么编辑configNet.h 包括以下的定义:
#define MOT_FCC_LOAD_FUNC sysMotFccEndLoad
LOAD_STRING:
在网络初始化过程中,作为initString参数,传递给muxDevLoad( )的初始化参数。这个字符串也一并传给endLoad()函数,它的内同取决于驱动的需要。
必须编辑endDevTbl()的定义(在configNet.h中规定包括在镜像中的ENDS)从而包含被加载的每一个设备的入口。
例如:
END_TBL_ENTRY endDevTbl [] =
{
{ 0, LOAD_FUNC_0, LOAD_STRING_0, BSP_0, NULL, FALSE },
{ 1, LOAD_FUNC_1, LOAD_STRING_1, BSP_1, NULL, FALSE },
{ 0, END_TBL_END, NULL, 0, NULL, FALSE },
};
上面的第一个参数规定设备号。在最后的FALSE 表示入口还没有被处理。在系统成功的加载驱动后,这个值变为TRUE。如果想要禁止系统自动加载驱动,那么可以把这个值设为TRUE。
这样,就准备好重新编译VxWorks 从而包括新的END 驱动。当新编译的VxWorks 启动时,系统给在table 中每一个设备按照列出来的顺序调用muxDevLoad()。
常见的一些配置宏定义如下:
? CPU:目标板的CPU
? TOOL:主机开发工具
? ROM_TEXT_ADRS:启动ROM的16进制入口地址,多数目标板设置为ROM的起始地址
? ROM_SIZE:ROM的16进制空间大小
? ROM_LOW_ADRS:VxWorks装入的起始地址
? ROM_HIGH_ADRS:boot ROM拷贝到RAM的起始地址
? LOCAL_MEM_LOCAL_ADRS:目标板存储空间的起始地址
? LOCAL_MEM_SIZE:固定(静态)存储器大小
? USER_RESERVED_MEM:保留内存大小
? RAM_HIGH_ADRS:拷贝boot ROM映像的目标地址
? ROM_BASE_ADRS:ROM起始地址
? ROM_TEXT_ADRS:boot ROM的入口地址,多数为ROM空间的起始地址
? ROM_WARM_ADRS:热启动的入口地址
? ROM_SIZE:ROM空间的大小
其中ROM_TEXT_ADRS和ROM_SIZE的定义必须和Makefile一致。