vxworks引导启动过程

vxworks引导启动过程
vxworks引导启动过程

一基本概念及引导概述

1 bootloader/bootrom/bootstrap

CPU上电经自复位的过程(由硬件时序逻辑决定的Power-On StrappingSequence)后,

指令指针指向一个固定的地址(after-reset startingpoint)。这个固定地址因体系架构而异:在一个基于ARM7TDMI core 的嵌入式系统中,系统在上电或复位时通常都从地址

0x00000000 处开始执行;在一个MIPS体系架构的嵌入式系统中,系统在上电或复位时通常都从地址0xBFC00000(0x1FC00000)处开始执行。

无论是ARM中的0x00000000,还是MIPS中的0x1FC00000,这个入口地址处往往存放

的就是系统的Boot Loader程序。这个地址往往映射(可参考具体datasheet的Memory Map)为Boot Rom的地址空间,这里的Boot Rom通常为NOR Flash或者SPI Flash(早期的可能为EEPROM等非易失性存储介质)。由此可见,bootloader(引导加载程序)是系统上电后运行的第一段软件代码。bootrom则是用来存储bootloader的ROM/Flash芯片。

当然bootrom(ROM/Flash)上不仅仅只是存储bootloader,往往还存储着系统映像、应用程序资源和用户配置数据等信息。这样,嵌入式设备每次重新上电后,总能加载系统和恢复上一次的配置。因为嵌入式设备中往往没有配备磁盘,SDRAM又是易失的,因此bootrom 上往往还存放着系统映像等数据(可能是压缩的)。

在嵌入式系统中,通常没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动微码),因此整个系统的加载启动任务就完全由Boot Loader来完成。此时,CPU只认得指令,因此bootloader一般以纯汇编指令开始,而不应该包含任何ELF格式的文件头信息(这些信息只有特定OS才能识别)。

bootstrap是bootloader的一部分,是最初级的引导,旨在初始化CPU、内存控制器、时钟、堆栈,目标是让CPU正常运作起来。我们可以认为bootloader = bootstrap program + boot image。boot image往往初始化最小OS内核,搭建网络下载通道,提供一个可以

交互的命令行,以便自我更新(update boot)或下载更新系统映像(update vxWorks)。bootloader通常都分为Stage1和Stage2两个阶段,这里的bootstrap program对应Stage1,boot image则对应Stage2。下面从代码构成角度入手,阐述VxWorks下的bootstrap program和boot image的含义。

在vxWorks中,若含有bootlader(即下文提到的Boot Image + Loadable Image组合类型),则bootstrap program主要是指romInit.s+bootInit.c,boot image主要是指有bootConfig.c、sysAlib.s、sysLib.c以及BSP目录下的其他文件编译链接而成。通常为了节省空间,boot image部分被压缩作为数据段存储在bootstrap program之后——bootrom.bin。bootstrap program是在ROM/Flash中运行的,当然为了执行更快,其后半部分也可能拷贝到RAM中执行。很显然,bootstrap program是不能压缩的,否则无法完成自举。

VxWorks映象由文本段(.text/.code),数据段(.data)和BSS段(.bss)组成。文本段相当于代码段,是由一些指令组成的;数据段就是由一些初始化过的全局和静态变量组成;BSS段也是由全局变量和静态变量组成,只不过他们都没有经过初始化。

2 VxWorks映象的类型

(1).VxWorks(Loadable binary VxWorks image)

RAM based VxWorks image, linked to RAM_LOW_ADRS. It is loaded into RAM via some external program such as a bootROM.This is the default development image.

(2).vxWorks_rom(Uncompressed ROMable binary VxWorks image)

RAM based image that starts in ROM. The ROM startup code copies the entireimage to RAM and then jumps to it. This image generally has a slower startup time, but faster execution time, than vxWorks_romResident.

(3).vxWorks_romCompress(compressed ROMable binary VxWorks image) Compressed RAM based image thatstartsin ROM. This image can fit almost twice the code as other ROM images.But it has the slowest boot time, since the image must be uncompressed. The run-time speed is the same as for vxWorks_rom.

(4).vxWorks_romResident(ROM-resident version binary VxWorks image)

ROM resident image. The program text remains in ROM, only the data is copied to RAM. This image has the fastest boot time and uses the least amount of RAM, but runsslower on boards with slow ROM access.

相关后缀的含义同bootrom。

我们可将VxWorks Image的文件类型划分为两类三种:

A.加载型映象(VxWorks类型)

(1)Loadable Image是包含用户程序的VxWorks操作系统映象,其不具备引导功能,需要借助bootloader引导程序通过网口或串口下载到RAM中。bootloader在此扮演了“搬运工”的角色。

B.可引导型映象

可引导型(Bootable)映象包含含有用户程序的VxWorks操作系统映象,并包括完整的引导代码,可以在系统上电后自动完成自身的引导。我们在前面已经分析过,该类映像往往由bootstrap program(romInit.s+romStart.c)和紧随其后的为vxWorks映像(可能被压缩)组成。

(2)ROM-based Image(压缩/没有压缩):即将Image直接烧入ROM/flash,运行时将Image拷入(如果压缩则需解压)RAM中运行。

(3)ROM-resident Image:Image的指令部分驻留在ROM中运行,仅将数据段部分拷入RAM。

注意,以上三种映象都是包含完整VxWorks操作系统的映象,其中后两种可以直接启动并运行起来,但是第一种不行,它必须借助另一个叫做Boot Image的映象(可以在Tornado 中的build->build bootrom中生成)才能运行起来,也就是利用Boot Image引导起来后通过网口或串口下载真正包含VxWorks的Loadable Image,然后才能运行起来。也即Boot Image往往和Loadable Image结合起来使用。

现在看来一共有四种映象文件,让我们看看它们的组成:

(1)Boot Image:包含一段起始引导程序(BootStrap Program)和一段ROM引导程序(ROM Boot Program)。

(2)Loadable Image:由操作系统VxWorks和应用组成的映象。

(3)ROM-based Image(压缩/没有压缩):包含一段叫做BootStrap Program的程序

+Loadable Image(即有操作系统VxWorks和应用组成的映象)。

(4)ROM-Resident Image:同上。

通过上面我们可以看出,ROM-based Image,ROM-Resident Image,Boot Image三种映象都包含一段叫做BootStrap Program的程序,可以把ROM引导程序的代码段和数据段拷贝到RAM中。同时,它具有启动功能。

三VxWorks映象启动流程

下面让我们看看三种VxWorks的启动过程:

1 BootImage+LoadableImage

注意:这里和下文的Boot Image是指存放在bootrom中的bootloader映像。

前面提到LoadableImage是依靠Boot Image加载启动的,首先由Boot Image中的BootStrap Program程序把ROM引导程序(ROM Boot Program)加载(如果压缩则需解压)到RAM中的RAM_HIGH_ADRS处,然后跳转到此处执行ROM引导程序,由ROM 引导程序负责一系列简单的硬件初始化(网口,串口等),开始下载Loadable Image(即包含应用的VxWorks操作系统)到RAM_LOW_ADRS,然后跳转到此处启动VxWorks操作系统。

下面的图一是一个简单的流程图,后面的图二是更为详细的流程图。

图一

图二(1)

图二(2)

引导过程成功以后,RAM中ROM引导程序占用的空间(从RAM_HIGH_ADRS开始)可以重新被系统利用。

2 ROM-basedImage(压缩/没有压缩)

这种映象由起始引导程序(BootStrap Program)和基于ROM的VxWorks映象组成。因此,这种bootrom的体积较大。BootStrap Program把基于ROM的VxWorks映象加载到内存的RAM_LOW_ADRS处,然后直接启动VxWorks操作系统(如果压缩则需解压)。图三是一个简图,图四是更为详尽的流程图。

图三

图四

3 ROM-residentImage

这种映象由起始引导程序(BootStrap Programs)和驻留ROM的VxWorks映象组成。VxWorks系统文本段(代码段)驻留在ROM,搬移程序负责将data段和bss段搬移到内存的RAM_LOW_ADRS处,直接启动VxWorks映像(含符号表)。此时,RAM_LOW_ADRS 是VxWorks映象的加载点,也是VxWorks数据段的起始点。

四VxWorks映象函数级启动过程

上一节主要是从映象的分类和各种映象的大致加载流程上看VxWorks的启动过程,这一节让我们从函数级看一下VxWorks的启动过程。

1 BootImage+LoadableImage

VxWorks借鉴了传统PC操作系统的引导原理,其将整个引导过程分为两个阶段:

1.1 BOOTROM启动

起始引导程序(BootStrap Program)驻留在ROM中,主要包含:

(1)汇编级的硬件初始化程序romInit.s,用于系统的基本初始化,设置一些重要寄存器的初始值,进行存储器的映射

(2)搬移程序bootInit.c,将ROM引导程序拷贝至RAM的高端地址RAM_HIGH_ADRS,然后跳转到此处执行ROM引导程序。

ROM引导程序运行,将可加载的VxWorks映象下载到内存的指定地址RAM_LOW_ADRS 处。

1.2 启动VxWorks内核

下面是具体的流程图:

图五

其中第一阶段的执行流程使用的是上图的左边的源文件中的那些函数

(romInit->romStart->usrInit->sysHwinit->usrKernelinit->usrRoot);第二阶段执行流程使用的是上图中右边源文件中的那些函数

(sysInit->usrInit->sysHwinit->usrKernelinit->usrRoot->usrAppInit)。下面具体解释:Stage 1:

(1)romInit.s : romInit() /*entry point for VxWorks in ROM*/

系统上电之后,首先调用的函数就是romInit(),其主要完成两个操作:将CPU设置为正确的工作状态,包括各个寄存器的值以及CPU的工作模式;初始化系统内存并建立堆栈。由于需要设置CPU模式,所以这里的代码必须由汇编代码完成,并且汇编也是建立堆栈的唯一选择。

?禁止中断,避免陷入不确定混乱状态。

?清除cache。

?初始化CPU基本寄存器,调用SDRAM初始化函数初始化UPM。

?初始化系统堆栈,在内存中建立起堆栈后,系统就具备了高级语言的执行条件。后面的代码可以用C实现。

?把启动类型(冷启动/热启动)放在堆栈上。

?直接跳转到bootInit.c : romStart()

(2)bootInit.c : romStart()/*generic ROM initialization*/

这是VxWorks中所执行的第一段C语言代码,但仍在ROM中执行。

?把ROMBoot Program的代码段和数据段从ROM复制到RAM中。

?完成程序映象的解压缩(如果映象是压缩版本的)。

?跳转到bootConfig.c: usrInit()开始执行ROM引导程序。

从这里开始,可引导型映象和加载型映象走上了相同的初始化道路。

(3)bootConfig.c : usrInit()

对于bootrom_uncmp和bootrom_res,在romStart()中直接跳转到usrInit()。对于压缩的bootrom,romStart()跳转到解压缩点,而bootConfig.c中的第一个函数为compressedEntry(),故压缩型bootrom解压后将跳转到compressedEntry()入口处,紧接着调用usrInit()。至于为什么压缩的bootrom需要compressedEntry这个桩函数(Stub Routine),详情参考后文《VxWorks/MIPS运行期的gp重定位》。

/

* compressedEntry - compressed entry point after decompression。

* This routine is the entry point after the bootroms decompress, if

* compression is utilized. This routine must be the first item of the

* text segment of this file.

*/

? VxWorks中第一个在RAM中执行的函数。执行操作系统内核所必须的初始化程序。? Cache程序库的初始化。

?清零系统的BSS段。

?初始化中断向量表。

?使硬件工作在一个“安静”的状态,尽量不产生各种中断或者异常。

?调用sysHwInit()初始化硬件。

?调用usrKernelInit()初始化内核的必要组件。

?调用KernelInit(),初始化VxWorks内核并产生usrRoot根任务。

?在usrRoot根任务中解析Bootline,产生bootCmdLoop任务,用于启动、加载VxWorks 映象。

此时,调试超级终端会有如下打印信息(printBootLogo()):

VxWorks System Boot

Copyright 1984-1998 Wind River Systems,Inc.

CPU: MPC860

Version: 5.4

BSP version: 1.2/0

Creation date: Aug 22002,09:19:47

Press any key to stopauto-boot...

3

接着,将调用自动引导程序autoboot(timeout),在指定时间timeout内,按任意键可停止自动启动,修改启动行参数(read and execute the ROM commands)。下一步将调用bootload()将指定主机目录下的VxWorks映象下载到目标板的RAM地址RAM_LOW_ADRS处,并跳转(go)到此处执行指令代码,启动VxWorks操作系统。

[VxWorks Boot]: p

boot device : cpm

unit number : 0

processor number : 0

host name : Michel

file name : c:/ftpRoot/vxWorks

inet on ethernet (e) :168.2.7.27:ffffff00

host inet (h) : 168.2.7.10

user (u) : target

Passwd(pw) : target

flags (f) : 0x0

―――――――――――――――――――――――――――

[VxWorks Boot]: @

boot device : cpm

unit number : 0

processor number : 0

host name : Michel

file name : c:/ftpRoot/vxWorks

inet on ethernet (e) :168.2.7.27:ffffff00

host inet (h) : 168.2.7.10

user (u) : target

Passwd(pw) : target

flags (f) : 0x0

Attached TCP/IPinterface to cpm0.

Attaching networkinterface lo0... done.

Stage 2:

(1)bootConfig.c :bootLoad()

加载VxWorks映象,并跳转到它的加载地址,具体流程如下。

usrBootLineInit()中strcpy (BOOT_LINE_ADRS,DEFAULT_BOOT_LINE);从FLASH中读出DEFAULT_BOOT_LINE配置的引导方式及映象文件。

bootload()->usrBootLineCrack (BOOT_LINE_ADRS,¶ms)获取BOOT_PARAMS,通过params.bootDev类型来决定从硬盘、软盘、闪存加载或通过网口、串口下载VxWorks 映象。

bootLoad (BOOT_LINE_ADRS, &entry);

{

scsiLoad();/* loada vxWorks image from a local SCSI disk */

fdLoad(); /* loada vxWorks image from a local floppy disk */

ideLoad();/* loada vxWorks image from a local IDE disk */

ataLoad();/* loada vxWorks image from a local ATA disk */

pcmciaLoad();/* loada vxWorks image from a PCMCIA disk device */

tffsLoad();/* loada vxWorks image from a TFFS Flash disk */

tsfsLoad();/* loada vxWorks image from a Target Server File System (TSFS) */

netLoad();/*downLoad a file from a remote machine via the network */ bootLoadModule();/*bootstrap load an object module into memory */

}

下载完成后,直接跳转到VxWorks系统映象起始地址(RAM_LOW_ADRS)处,从系统入口点(VxWorks image entrypoint)开始执行,入口函数为sysInit():

go (entry); /*... and never return */

(2)sysALib.s : sysInit()

与romInit.s: romInit()的初始化过程类似,但不再初始化SDRAM。

(3)usrConfig.c :usrInit()

设置cache的工作模式,板级硬件初始化,初始化Wind内核,启动usrRoot()根任务。(4)usrConfig.c : usrRoot()

初始化内存,系统时钟,I/O系统,标准输入输出错,异常处理,最后会调用usrAppInit.c 中的usrAppInit()进行用户级应用模块的初始化。

此时调试超级终端打印如下信息,Boot引导完成。

/*VXWORKS Image GettingLoaded*/

Loading (881680)

Starting at 0x10000…

Attached TCP/IPinterface to cpm unit 0

Attaching networkinterface lo0... done.

VxWorks

Copyright 1984-1998 WindRiver Systems,Inc.

CPU : MPC860

vxWorks : 5.4

BSP version: 1.2/0

Creation date: Aug 22000

WDB : Ready

2 ROM-based Image(压缩/没有压缩)

和上面那种启动方式相比,这种启动方式省去了一些步骤,执行完romStart()之后就已经将VxWorks加载到RAM中了,因此,下一步就是把控制权交给VxWorks,由VxWorks从usrEntry()开始执行即可。下面是具体的流程:

(1)romInit.s : romInit()

同上。

(2)romStart.c : romStart()

rules.vxWorks中根据映像类型是vxWorks_romCompress、vxWorks_rom或

vxWorks_romResident,将ROM_FLAGS_EXTRA定义为CC_ROM_CMP_FLAGS、CC_ROM_CPY_FLAGS或CC_ROM_RES_FLAGS(defs.vxWorks中定义),其中分别定义了ROM_COMPRESS、ROM_COPY或ROM_RESIDENT宏。项目wpj文件在romInit.o 和romStart.o的BUILDRULE中引入了ROM_FLAGS_EXTRA。

?把基于ROM的VxWorks映象的代码段(如果是VxWorks_romResident映象,则不拷贝代码段)和数据段从bootrom复制到RAM当中。

?完成程序映象的解压缩(如果映象是压缩版本的)

?跳转到usrEntry.c: usrEntry()

(3)usrEntry.c : usrEntry()

? usrEntry - entry point for _romCompress and _rom images.

rules.vxWorks中定义了partialImage.o的编译规则,当非DEFAULT_RULE(vxWorks)类型时,usrEntry.o将会安插到$(PRJ_OBJS_FOR_LD_PARTIAL)之前。而

PRJ_OBJS_FOR_LD_PARTIAL=PRJ_OBJS=prjObjs.lst,其中第一个目标文件为sysAlib.o,这样usrEntry()取代sysInit()了成为vxWorks的入口。

-------------------------------------------------------------------------------------------------------- partialImage.o: $(LDDEPS) $(PRJ_OBJS) $(EXTRA_MODULES) $(COMPONENT_LIBS) \ $(patsubst -l%,lib%.a,$(LIBS)) $(CC_LIB) $(PRJ_OBJS_FILE)

- @ $(RM) $@

$(CC) $(CFLAGS) $(OPTION_OBJECT_ONLY) $(VERSION_C)

ifneq ($(findstring vxWorks_rom, $(DEFAULT_RULE)),)

$(CC) $(CFLAGS) $(OPTION_OBJECT_ONLY) $(USR_ENTRY_C)

$(LD_PARTIAL) usrEntry.o $(PRJ_OBJS_FOR_LD_PARTIAL) \

$(EXTRA_MODULES) version.o $(LD_PARTIAL_START_GROUP) \

$(COMPONENT_LIBS) $(LD_LINK_PATH) $(LIBS) \

$(LD_PARTIAL_END_GROUP) $(CC_LIB) -o $@

else

$(LD_PARTIAL) $(PRJ_OBJS_FOR_LD_PARTIAL) $(EXTRA_MODULES) \

version.o $(LD_PARTIAL_START_GROUP) $(COMPONENT_LIBS) \

$(LD_LINK_PATH) $(LIBS) $(LD_PARTIAL_END_GROUP) $(CC_LIB) -o $@

endif

--------------------------------------------------------------------------------------------------------

?控制权移交给usrInit()

(4)usrConfig.c : usrInit()

执行操作系统内核所必须的初始化程序。

? Cache程序库的初始化。

?清零系统的BSS段。

?初始化中断向量表。

?使硬件工作在一个“安静”的状态,尽量不产生各种中断或者异常。

?控制权移交给KernelInit(),产生usrRoot根任务,最后会调用usrAppInit.c中的usrAppInit()进行用户级应用模块的初始化。

此时,调试超级终端会有如下打印信息:

/*VXWORKS Image GettingLoaded*/

Loading (881680)

Starting at 0x10000…

Attached TCP/IPinterface to cpm unit 0

Attaching networkinterface lo0... done.

VxWorks

Copyright 1984-1998 WindRiver Systems,Inc.

CPU : MPC860

vxWorks : 5.4

BSP version: 1.2/0

Creation date: Aug 22000

WDB : Ready

3 ROM-residentImage

.text代码段驻留在ROM/.Flash中运行,.data数据段和.bss段需要拷贝重定位到RAM中,且所使用的堆栈空间亦在RAM中。启动流程和vxWorks_rom*映像基本相同,稍微不同的是romStart()中直接跳转到usrInit,而不是usrEntry。至于为什么vxWorks_rom(Compress)需要usrEntry这个桩函数(Stub Routine),详情参考后文《VxWorks/MIPS运行期的gp重定位》。

五使用Tornado编译VxWorks映象

Tornado2.2\target\config\all下的bootConfig.c/bootInit.c/usrConfig.c为通用的

bootrom/vxworks代码模版。其中,bootConfig.c/bootInit.c是用来生成bootrom的,是通过工具栏里的Build->Build BootRom生成的,相当于命令行;usrConfig.c是用于生成vxworks的。

需要注意的是如果使用手动编译,则编译的是usrConfig.c文件;如果在Tornado开发环境下编译,则编译的是Tornado根据用户配置自动生成的prjConfig.c文件。

/* prjConfig.c - dynamicaly generatedconfiguration file */

工程下编译就要按照prjConfig.c里各个程序的封装顺序执行。

相关主题
相关文档
最新文档