在讲初始化流程之前,我们先了解下VxWorks的三种映像类型。要搞清楚映像结构,需要先了解下VxWorks的内存空间分配。所以我们先从框架入手。
根据应用场合不同,vxworks映像可以分成三类:可加载的映像、基于ROM的映像和驻留ROM映像。
在RAM中运行,不包含搬移程序,需要借助一些外部程序如BootROM才能加载到RAM的低端RAM_LOW_ADRS地址处。
目标板上电后,由烧录在BootROM中的起始引导程序Bootstrap将ROM引导程序拷贝到RAM的高端地址RAM_HIGH_ADRS处,
并跳转至该地址执行ROM引导程序,将指定的主机目录下的可加载的vxworks映像下载到目标板的RAM地址RAM_LOW_ADRS
处,并跳转到此处执行。
将Image直接烧入ROM,执行时将Image拷入RAM中执行。
基于ROM的压缩的映像,主要是为了节约存储空间,在从ROM拷贝到RAM的过程中需要解压缩,因此与未压缩的映像相比,它
的引导过程相对较慢,但两者在RAM中的运行速度是一样的。
目标板上电后,首先运行BootROM中的引导搬移程序,但仅将映像的数据段和BSS段拷贝到RAM地址RAM_LOW_ADRS处,映
像的代码段仍旧留在ROM中(与前两种映像的区别),从ROM中开始执行。
优点是具有最快的引导速度,占用最少的RAM空间,适用于RAM空间有限的目标板。但由于该映像在ROM中运行,运行速度在
三种映像中是最慢的。
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。
代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常数变量,如字符串常量等。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张和收缩。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被删除。
栈(stack):栈又称堆栈,是用户存放程序临时创建的局部变量。除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存、恢复调用现场。
romInit.s: romInit()
设置机器状态字及其他硬件相关寄存器,关闭中断,禁止程序和数据cache,初始化内存,并设置堆栈指针。
bootInit.c:romStart()
romStart的主要作用是将ROM中的程序搬移到RAM中,包括引导程序和内核映像,然后清理内存。
如果是基于ROM的压缩代码,则需要先解压,然后拷贝到内存地址,接着从RAM_HIGH_ADRS这个地址开始执行。
如果是驻留ROM的代码,则只是将数据段拷贝到内存中,然后在片内执行usrInit函数。如果是基于ROM的未压缩代码,则执行入口是usrInit。
usrConfig.c: usrInit()
设置cache工作模式,板级硬件初始化,调用sysHwInit(),usrKernelInit(),KernekInit(),初始化Win内核,产生根任务usrRoot()。
usrConfig.c: usrRoot()
初始化内存,系统时钟,I/O系统,标准输入输出,异常处理,外围设备初始化,产生任务bootApp()。
bootApp.c: bootApp()
启动一个bootAppTask,并设置Task优先级为60,option为0,Stack Size为10K。
bootApp.c: bootAppTask ()
执行bootShellAutobootFunc, 接着执行autoboot,判断是否为自动启动。
bootAppShell.c: autoboot()
延迟7S,以默认参数启动,若等待超时,执行bootLoad(),加载vxworks映像,并转向它进行重启;
若用户按键中断,执行bootAppShell (),启动命令用于配置vxworks启动参数,用户输入@,则进入bootLoad()。
bootApp.c: bootLoad()
加载VxWorks映像文件到内存,设置启动参数。我们现在使用的是bootFtpLoad。
sysALib.s: sysInit()
锁住中断,关闭cache(如果使用了),初始化处理器的寄存器(包括C堆栈指针)至缺省值。最后会跳转到usrInit函数执行。
prjConfig.c: usrInit()
调用sysStart() 对bss清零,调用cacheLibInit()设置cache工作模式,调用excVecInit(),初始化所有系统和缺省中断向量,调用sysHwInit()对板级硬件初始化;调用usrKernelInit()初始化win内核。
usrKernel.c: usrKernelInit ()
调用taskLibInit()初始化Task库,计算内存池结束地址memPoolEndAdrs,设置内核初始化参数_KERNEL_INIT_PARAMS kIP,最后调用kernelInit(KIP)。
kernelLib.c: kernelInit ()
初始化并启动内核,从内存池顶部创建根堆栈和TCB,最后创建Root Task用于执行usrRoot的初始化。
prjConfig.c: usrRoot()
初始化内存,系统时钟,I/O系统,标准输入输出,异常处理,添加用户应用程序。
usrAppInit.c: usrAppInit
在usrRoot函数最后会执行usrAppInit,从此处跳到用户代码处执行。
至此,VxWorks6.9完整的初始化流程讲解完毕。网上有很多讲VxWorks初始化的文章,但是比较老,有的还是基于5.x版本讲的,已经过时。本文是我基于P2020硬件平台,运行Vxworks6.9版本实际调试分析出来的结果。每个接口是否调用到,我亲自编译运行验证过,可供大家调试Vxworks6.9时进行参考。