转载地址:http://bbs.2beanet.com/vxworks-f10/vxworks-t3385.html
VxWorks的引导程序叫VxLd,由Tornado工具vxsys.com写入。它运行后会从当前磁盘的根目录下加载BOOTROM.SYS(此文件必须连续存放,因为VxLd很简单,还不认识任何文件系统),加载地址为0x8000。这个步骤通过调用BIOS INT13完成。加载完成后跳转到0x8000执行。VxWorks操作系统的第一条指令就存放于0x8000的地方(注:这是bootrom;对于vxWorks image为0x108000;或者相反)。注意在PC目标机上,VxWorks和BIOS的关系。VxWorks假定BIOS已经正确地初始化系统硬件,包括内存,PCI总线等,所以pc386,pc486等BSP就省掉了很多工作。然而VxWorks启动后,不会用到BIOS的任何功能,这和DOS不一样。因为VxWorks运行于保护模式,而BIOS功能必须从实模式下调用(也许有人可以给我们说说如何在保护模式下如何调用BIOS功能,当然这是一个高级话题)。实际在一般正常情况下,当VxWorks运行后,BIOS就彻底消失了。
romInit.s:定义了系统入口romInit函数,它是系统上电后最先执行的代码。romInit中完成禁止CPU中断,设置初始栈指针,配置DRAM控制器等少量CPU设置之后调用第一个函数romStart。进一步的硬件初始化由sysLib.c中定义的sysHwInit函数完成。在BSP开发中,romInit.s只要使RAM工作起来就行,不用进行太多的硬件初始化。
romInit.s中的硬件初始化会在sysLib.c或sysALib.c重复一遍。因为VxWorks程序只需要BootRom的参数串和启动类型代码,而不遵循依赖BootRom的硬件初始化(除了RAM初始化)。VxWorks启动时会重新初始化CPU和其他所有硬件。RAM也可在VxWorks中再初始化一遍,对程序运行不会有影响。BootRom和VxWorks的无关性是个基本原则,若不遵循这个原则,就会出现VxWorks和BootRom的关联修改。
/*******************************************************************************
*
* romInit - entry point for VxWorks in ROM
*
* romInit (startType)
* int startType; /@ only used by 2nd entry point 只有热复位使用,从栈中取参数,冷复位直接指定 @/
*/
/* cold start entry point in REAL MODE(16 bits)以下执行的是VxWorks系统的第一条指令。此时CPU还处于实模式,程序只能访问1M内存空间,缺省的指令为16-bit代码。需要尽快将CPU切换到保护模式 */
romInit:
_romInit:
cli /* LOCK INTERRUPT 禁止中断*/
jmp cold /* offset must be less than 128 */
/* warm start entry point in PROTECTED MODE(32 bits) */
.balign 16,0x90
romWarmHigh: /* ROM_WARM_HIGH(0x10) is offset */
cli /* LOCK INTERRUPT */
movl SP_ARG1(%esp),%ebx /* %ebx has the startType */
jmp warm
/* warm start entry point in PROTECTED MODE(32 bits) */
.balign 16,0x90
romWarmLow: /* ROM_WARM_LOW(0x20) is offset */
cli /* LOCK INTERRUPT */
cld /* copy itself to ROM_TEXT_ADRS */
movl $ RAM_LOW_ADRS,%esi /* get src addr (RAM_LOW_ADRS) */
movl $ ROM_TEXT_ADRS,%edi /* get dst addr (ROM_TEXT_ADRS) */
movl $ ROM_SIZE,%ecx /* get nBytes to copy */
shrl $2,%ecx /* get nLongs to copy */
rep /* repeat next inst ECX time */
movsl /* copy nLongs from src to dst */
movl SP_ARG1(%esp),%ebx /* %ebx has the startType */
jmp warm /* jump to warm */
/* copyright notice appears at beginning of ROM (in TEXT segment) */
.ascii "Copyright 1984-2002 Wind River Systems, Inc."
/* cold start code in REAL MODE(16 bits) */
.balign 16,0x90
cold:
.byte 0x67, 0x66 /* next inst has 32bit operand */
lidt %cs:(romIdtr - romInit) /* load temporary IDT */
.byte 0x67, 0x66 /* next inst has 32bit operand */
lgdt %cs:(romGdtr - romInit) /* load temporary GDT */
/* switch to protected mode */
mov %cr0,%eax /* move CR0 to EAX */
.byte 0x66 /* next inst has 32bit operand */
or $0x00000001,%eax /* set the PE bit */
mov %eax,%cr0 /* move EAX to CR0 */
jmp romInit1 /* near jump to flush a inst queue */
romInit1:
.byte 0x66 /* next inst has 32bit operand */
mov $0x0010,%eax /* set data segment 0x10 is 3rd one */
mov %ax,%ds /* set DS */
mov %ax,%es /* set ES */
mov %ax,%fs /* set FS */
mov %ax,%gs /* set GS */
mov %ax,%ss /* set SS */
.byte 0x66 /* next inst has 32bit operand */
mov $ ROM_STACK,%esp /* set lower mem stack pointer */
.byte 0x67, 0x66 /* next inst has 32bit operand */
ljmp $0x08, $ ROM_TEXT_ADRS + romInit2 - romInit
/* temporary IDTR stored in code segment in ROM */
romIdtr:
.word 0x0000 /* size : 0 */
.long 0x00000000 /* address: 0 */
/* temporary GDTR stored in code segment in ROM */
romGdtr:
.word 0x0027 /* size : 39(8 * 5 - 1) bytes */
.long (romGdt - romInit + ROM_TEXT_ADRS) /* address: romGdt */
/* temporary GDT stored in code segment in ROM */
.balign 16,0x90
romGdt:
/* 0(selector=0x0000): Null descriptor */
.word 0x0000
.word 0x0000
.byte 0x00
.byte 0x00
.byte 0x00
.byte 0x00
/* 1(selector=0x0008): Code descriptor */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 2(selector=0x0010): Data descriptor */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x92 /* Data r/w, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 3(selector=0x0018): Code descriptor, for the nesting interrupt */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 4(selector=0x0020): Code descriptor, for the nesting interrupt */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* cold start code in PROTECTED MODE(32 bits) */
.balign 16,0x90
romInit2:
cli /* LOCK INTERRUPT */
movl $ ROM_STACK,%esp /* set a stack pointer */
#if defined (TGT_CPU) && defined (SYMMETRIC_IO_MODE)
movl $ MP_N_CPU, %eax
lock
incl (%eax)
#endif /* defined (TGT_CPU) && defined (SYMMETRIC_IO_MODE) */
/* WindML + VesaBIOS initialization */
#ifdef INCLUDE_WINDML
movl $ VESA_BIOS_DATA_PREFIX,%ebx /* move BIOS prefix addr to EBX */
movl $ VESA_BIOS_KEY_1,(%ebx) /* store "BIOS" */
addl $4,%ebx /* increment EBX */
movl $ VESA_BIOS_KEY_2,(%ebx) /* store "DATA" */
movl $ VESA_BIOS_DATA_SIZE,%ecx /* load ECX with nBytes to copy */
shrl $2,%ecx /* get nLongs to copy */
movl $0,%esi /* load ESI with source addr */
movl $ VESA_BIOS_DATA_ADDRESS,%edi /* load EDI with dest addr */
rep
movsl /* copy BIOS data to VRAM */
#endif /* INCLUDE_WINDML */
/*
* Don't call romA20on if booted through SFL. romA20on does ISA
* I/O port accesses to turn A20 on. In case of SFL boot, ISA
* I/O address space will not be initialized by properly by the
* time this code gets executed. Also, A20 comes ON when booted
* through SFL.
*/
#ifndef INCLUDE_IACSFL
call FUNC(romA20on) /* enable A20 */
cmpl $0, %eax /* is A20 enabled? */
jne romInitHlt /* no: jump romInitHlt */
#endif /* INCLUDE_IACSFL */
movl $ BOOT_COLD,%ebx /* %ebx has the startType */
/* copy bootrom image to dst addr if (romInit != ROM_TEXT_ADRS) */
warm:
ARCH_REGS_INIT /* initialize DR[0-7] CR0 EFLAGS */
#if (CPU == PENTIUM) || (CPU == PENTIUM2) || (CPU == PENTIUM3) || /
(CPU == PENTIUM4)
/* ARCH_CR4_INIT /@ initialize CR4 for P5,6,7 */
xorl %eax, %eax /* zero EAX */
movl %eax, %cr4 /* initialize CR4 */
#endif /* (CPU == PENTIUM) || (CPU == PENTIUM[234]) */
movl $romGdtr,%eax /* load the original GDT */
subl $ FUNC(romInit),%eax
addl $ ROM_TEXT_ADRS,%eax
pushl %eax
call FUNC(romLoadGdt)
movl $ STACK_ADRS, %esp /* initialise the stack pointer */
movl $ ROM_TEXT_ADRS, %esi /* get src addr(ROM_TEXT_ADRS) */
movl $ romInit, %edi /* get dst addr(romInit) */
cmpl %esi, %edi /* is src and dst same? */
je romInit4 /* yes: skip copying */
movl $ FUNC(end), %ecx /* get "end" addr */
subl %edi, %ecx /* get nBytes to copy */
shrl $2, %ecx /* get nLongs to copy */
cld /* clear the direction bit */
rep /* repeat next inst ECX time */
movsl /* copy itself to the entry point */
/* jump to romStart(absolute address, position dependent) */
romInit4:
xorl %ebp, %ebp /* initialize the frame pointer */
pushl $0 /* initialise the EFLAGS */
popfl
pushl %ebx /* push the startType */
movl $ FUNC(romStart),%eax /* jump to romStart */
call *%eax
/* just in case, if there's a problem in romStart or romA20on */
romInitHlt:
pushl %eax
call FUNC(romEaxShow) /* show EAX on your display device */
hlt
jmp romInitHlt
sysALib.s:这是VxWorks中另外一个汇编代码文件,实现了RAM中VxWorks的入口函数sysInit。该函数代码位于VxWorks程序映像的开始,保证实现BootRom到VxWorks的成功跳转。重复实现romInit的部分功能,如禁止中断和初始化栈等,然后跳转到usrInit。
sysLib.c:该文件是BSP的主要源代码文件,不像上两个系统初始化文件,sysLib.c没有明显执行流程,而为上层代码提供硬件相关的服务接口。主要函数有:
sysHwInit:目标机核心硬件初始化,如片选、中断、系统时钟等;
sysHwInit2:目标机附加硬件初始化,如辅助时钟等;
sysPhysMemTop:取物理RAM内存最大地址;
sysMemTop:取VxWorks可用内存的最大地址,允许用户在物理RAM顶保留空间;
sysToMonitor:用于系统热复位。
VxWorks启动顺序:从宏观来看,一般是先加载BootRom;BootRom再加载VxWorks应用,并跳转到VxWorks的入口sysInit执行;VxWorks有可能根据启动脚本文件加载应用模块。整个启动过程完成后,系统进入多任务环境运行。
从文件的角度来看启动过程,按启动顺序列出相关文件如下:
BootRom
romInit.s:实现系统初始化入口romInit,完成最基本的CPU初始化,如禁止中断和片选初始化等,为后续启动作好准备。完成后跳转到romStart执行。
bootInit.c:实现系统第一个C函数入口romStart。主要完成程序映像中各段到RAM中的复制,各种程序映像在此分支,完成后调用usrInit函数。
bootConfig.c:实现usrInit函数,完成进入多任务环境前所有的初始化工作,完成后进入多任务环境,usrRoot为第一个系统任务,创建tBoot任务,tBoot任务完成VxWorks映像的加载。
VxWorks
sysALib.s:实现VxWorks的专用入口sysInit。假设CPU基础硬件初始化完成,简单初始化CPU后跳转到usrInit。
prjConfig.c:实现usrInit函数,完成进入多任务环境前所有的初始化工作。
usrKernel.c:实现usrKernelInit函数,使系统进入多任务环境。
prjConfig.c:实现usrRoot任务函数,完成操作系统一些上层初始化后,调用usrAppInit,完成应用代码必要的初始化,应用代码可能会在这里创建多个任务。
ROM启动VxWorks
romInit.s:实现系统初始化入口romInit,完成最基本的CPU初始化,如禁止中断和片选初始化等,为后续启动作好准备。完成后跳转到romStart执行。
romStart.c:c:实现系统第一个C函数入口romStart。主要完成程序映像中各段到RAM中的复制,各种程序映像在此分支,完成后跳转sysInit()执行。
后续步骤同前面的VxWorks顺序。