Vxworks启动代码usrRoot()函数分析(一)

本文详细剖析了VxWorks操作系统启动过程中的关键步骤,包括内存池初始化、MMU初始化、时钟设置、串口驱动安装及标准IO配置等内容。

今天到了星期日下午,开始分析usrRoot()函数,看看这个函数实现了哪些功能。

       (1) memInit (pMemPoolStart, memPoolSize);         /* initialize memory pool */

        我们知道在romstart函数中已经对内存进行了清零,这个内存池是干什么用的呢?搜了半天也没有资料具体说到底是如何初始化内存的,根据以前调试QNX的经验来看,我个人觉得这一步很可能为了确保相应内存的清零操作。

         (2) usrMmuInit ();                              /* initialize the mmu */

         初始化MMU单元,这个比较容易理解,MMU就是内存管理单元,负责管理虚拟地址,可以保证每个用户进程都有自己独立的地址空间使用,及时两个不同的进程读写相同的内存虚地址,实际上读写的物理地址是不一样的。这里就初始化MMU单元,打开函数可以看到,针对不同CPU类型加载相应的库函数进行初始化。

         (3)时钟设置

         sysClkConnect ((FUNCPTR) usrClock, 0);         /* connect clock ISR连接系统时钟中断服务程序*/

         我们知道,作为一个多任务操作系统,任务上下文切换是最基础的功能,系统调度用到的就是系统时钟中断,这里的时钟设置就提供了这样的功能。有了这个机制,接下来才可能实现多线程。其中挂接的中断处理程序在什么地方呢?原来VxWorks提供的usrClock()函数是系统缺省时钟中断处理函数,用来调用计数器函数tickAnnounce(),实现系统计数器的作用。

         sysClkRateSet (SYS_CLK_RATE);      /*set system clock rate设置每秒钟系统时钟中断次数,默认中断频率为60,一般在60到100,但不能大于600,也就是1s产生60次中断,大概是16.67ms*/

         这里有一个有意思的话题,就是按照默认的中断频率60次,是不是设置的越高实时性就越高呢?其实并不是这样的,VxWorks手册建议不要将时钟率设得太高,否则它就由硬实时变得趋向于软实时了。因为过高的时钟率使得内核调度频繁进入,更可能导致一些低优先级的硬件中断不能得到及时响应。

          sysClkEnable ();                                  /* start it使能系统时钟中断*/

         (4) selectInit (NUM_FILES);这个函数是干啥的呢?说是_func_selWakeupListInit函数需要其先进行初始化

         (5) iosInit (NUM_DRIVERS, NUM_FILES, "/null");,初始化IO系统,这里面限制了最多同时打开20个设备以及50个文件,也申请一些内存空间,包括设备表,设备的驱动函数表等。

         (6) ttyDrv();                                  /*install console driver */

         ttyDrv是一个字符型设备,负责串口与IO系统之间的交互。设备驱动的初始化过程首先调用系统函数ttyDrv(),该函数通过调用iosDrvInstall()将ttyOpen()、ttyIoctl()、tyRead()、tyRead、tyWrite安装到系统驱动函数表中,供I/O系统调用。其实理解起来一点都不难,就像我之前写的QNX 的SD卡driver的流程一样,负责底层鱼上层的交互。驱动模块初始化成功后,应用程序就可以用标准的I/O函数read()和write()收发数据了。

         有一个问题是,ttyDrv初始化的是哪个串口呢?往下看。

         在下面一些代码中就找到了一个可用的串口,就是sprintf (tyName, "%s%d", "/tyCo/", ix);

于是就找到了/tyCo/0,ttyDrv()实现了驱动函数与IO系统标准POSIX接口的对接,然后通过

(void) ttyDevCreate (tyName, sysSerialChanGet(ix), 512, 512);创建一个串口0的驱动程序,如果是系统CONSOLE_TTY口的话,就打开,并且进行设置。

                   consoleFd =open (consoleName, O_RDWR, 0);

                   (void) ioctl(consoleFd, FIOBAUDRATE, CONSOLE_BAUD_RATE);

                   (void) ioctl(consoleFd, FIOSETOPTIONS, OPT_TERMINAL);

         通过

             ioGlobalStdSet(STD_IN,  consoleFd);

             ioGlobalStdSet (STD_OUT,consoleFd);

             ioGlobalStdSet (STD_ERR,consoleFd);

         将标准输入输出定位到控制台上,就可以实现使用printf实现对控制台的调用了。

          (7)  接下来初始化一些结构、信号、管道、调试信息、标准IO函数库、信号队列、信号量、线程库、消息队列,以及一些POSIX功能支持。

         dosFsLibInit( 0 ) dosFsLibInit中调用iosDrvInstall将7个函数指针填入驱动程序表中,并得到一个驱动号表中各函数的入口对应文件系统提供的相应函数。

          (8)  /*initialize USB components */

         包含了一系列的USB设备初始化,包括USBhost协议栈、鼠标、键盘、打印机、扬声器等等。

         (9) SCSI设备初始化

         什么是SCSI?在Tornado DeviceDriver Workshop一书中解释为Small Computer System Interface,其目的为提供独立的设备接口,其优点在于一个控制器就可以控制多个外设,这就提供了一种驱动编写方法,以后再研究。

         (10)对ideDrvIDE 硬盘的驱动、SATA硬盘的支持、PCMCIA卡、tffs flash文件系统、对于浮点数软件以及硬件计算的支持、任务调度工具、时间工具、设置环境变量、模块管理器、引导设备初始化等。

         (11) usrNetInit()网络设备初始化。

         稍后再仔细对SCSI设备以及usrNetInit()网络初始化进行分析。

<think>好的,用户问的是VxWorks启动任务的text位置。首先,我需要回忆VxWorks的相关知识。VxWorks启动任务应该是指启动后的第个任务,通常是tTask或者usrRoot,负责初始化系统。用户提到的text位置,应该是指代码段在内存中的位置。 接下来,我需要确认VxWorks的内存布局。系统启动时,镜像加载到内存中,包括text段、data段、bss段等。对于任务来说,每个任务的代码段可能存放在哪里呢?如果是内核任务,可能链接到系统镜像的text段中,位于低端内存。如果是动态加载的任务,比如RTP(Real-Time Process),代码可能在动态内存区域,比如高端内存。 然后,需要考虑VxWorks的不同版本和配置。比如经典内核和RTP的区别。经典模式下,所有任务共享内核的text段,所以启动任务的代码应该在内核的text区域。而RTP有独立的地址空间,代码段可能在各自的加载地址。 还要想到内存分区的管理,比如系统是否有MMU,是否启用内存保护。如果有MMU,text段可能是只读的,并且地址固定。可能需要查看链接脚本或内存映射表来确定具体位置。 用户可能的问题背景是什么?可能是开发过程中需要调试启动任务,或者优化内存布局,或者涉及到代码重定位的问题。需要确保回答准确,同时给出查找具体地址的方法,比如使用符号查看工具或读取任务信息结构体。 还要注意语法和格式要求,使用中文,数学公式用$...$,独立公式用$$...$$。虽然这个问题可能不涉及数学公式,但需要保持结构清晰,分点说明。 最后,检查是否有遗漏点,比如VxWorks启动流程,任务创建时如何指定入口函数,以及入口函数的链接地址。确保回答覆盖了用户的问题,并帮助用户理解如何定位text位置,包括具体的方法和工具。</think>关于VxWorks启动任务的text段位置,其具体实现与系统配置密切相关。以下从技术角度分步骤说明: 1. **内核镜像布局** VxWorks系统镜像通过链接脚本(如`linkSyms.c`)确定内存布局。text段通常位于`TEXT_ADRS`定义地址,例如: ```c #define TEXT_ADRS 0x10000 /* ARM架构典型基地址 */ ``` 启动代码`usrInit()`作为入口函数,其机器码就存放在该区域。 2. **任务控制块(TCB)关联** 当创建启动任务(如`tTask`或`usrRoot`)时,内核通过`taskInit()`设置TCB的入口函数指针: ```c taskInit(taskId, priority, options, stackSize, (FUNCPTR)usrRoot, /* 入口函数地址 */ arg1, arg2, ..., argn); ``` 这里的`usrRoot`函数地址直接指向内核text段的符号地址。 3. **地址查询方法** - 使用`lkAddr`命令查看符号地址: ``` lkAddr "usrRoot" ``` 输出示例:`0x000105c4` - 通过`taskInfoGet()`获取TCB信息: ```c TASK_ID tid = taskIdSelf(); TASK_DESC taskDesc; taskInfoGet(tid, &taskDesc); printf("Entry point: 0x%08x\n", taskDesc.entry); ``` 4. **内存保护机制影响** 若启用MMU(如VxWorks 7的RTP模式),text段会被映射到虚拟地址空间。此时需通过`virtToPhys()`转换物理地址: ```c PHYS_ADDR physAddr = virtToPhys((void*)taskDesc.entry); ``` 5. **典型地址范围参考** | 架构 | text段起始地址 | 典型大小 | |-----------|-----------------|----------| | ARM Cortex-A9 | 0x00100000 | 2MB | | x86_64 | 0x00400000 | 4MB | | PowerPC e500 | 0x00010000 | 1MB | 注:实际地址需参考具体BSP的`config.h`和链接脚本配置。调试时可结合`objdump -t vxWorks`反查符号地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值