在usrconfig.c中的包含 bootFsLoadInit(), configAll.h 添加 两个宏定义
/* Define for FS */
#define BOOTAPP /* add by maketure at 20180509 */
#define INCLUDE_DOSFS /* add by maketure at 20180509 */
(方案1)在workbench中-->open development shell 进入bsp目录,输入make bootrom.bin
(方案2)在workbench中,在工程右键选择Builds Options-->set Active build Spec...-->选择需要生成二进制文件格式
workbench生成的bootrom本身的格式就是elf,故只要重命名
(1)P2020相关系列
在workbench中-->open development shell 进入对应的库目录,然后 make TOOL=e500v2diab CPU=PPC32
(2)ZYNQ系列
make CPU=ARMARCH7 TOOL=diab
make CPU=ARMARCH7 TOOL=diab VXBUILD=SMP
make CPU=ARMARCH7 TOOL=gnu
make CPU=ARMARCH7 TOOL=gnu VXBUILD=SMP
(1) ioTaskStdSet 任务级别重定向 ioGlobalStdSet全局的
void spyComTask(int freq, FUNCPTR printRtn) {
int delay = freq * sysClkRateGet();
int consoleFd = open("/tffs1/output.txt", 2, 0); //把spy任务输出重定向到 tffs里的output.txt文件
ioTaskStdSet(0, STD_IN, consoleFd);
ioTaskStdSet(0, STD_OUT, consoleFd);
ioTaskStdSet(0, STD_ERR, consoleFd);
void spyComTask(int freq, FUNCPTR printRtn) {
int delay = freq * sysClkRateGet();
int consoleFd = open("/tffs1/output.txt", 2, 0); //把spy任务输出重定向到 tffs里的output.txt文件ioTaskStdSet (0, STD_IN, consoleFd);ioTaskStdSet (0 ,STD_OUT, consoleFd);ioTaskStdSet (0, STD_ERR, consoleFd);
while (TRUE) {
spyReportCommon(printRtn);
taskDelay(delay);
}
}
BootRom中的重定向 打开target\config\all\usrconfig.c文件,可以找到这样一行代码: consoleFd = NONE;
此consoleFd变量即标准输入输出句柄,此时为空。
同样,可以找到如下的三行代码:
ioGlobalStdSet (STD_IN, consoleFd);
ioGlobalStdSet (STD_OUT, consoleFd);
ioGlobalStdSet (STD_ERR, consoleFd);
此三行代码的意思是将标准输入输出定向到consoleFd。在这两段代码之间有打开诸如串口、PC console等过程,并将其打开的句柄赋给了 consoleFd,这样就将其标准输入输出定向到PC console等。
同样,如果在定向之前,即ioGlobalStdSet函数之前打开别的I/O设备,如socket、文件、管道等的话,那么标准输入输出就定向到socket、文件、管道等。一般情况下,用户采用串口作为输入输出操作接口,所以我们一般将标准输入输出定向到串口。那么,怎么将标准输入输出定向到串口呢?按照以上原理,只要在ioGlobalStdSet函数之前打开相应的串口并将所打开的串口句柄赋给consoleFd就可以了。实现代码如下:
/*打开串口,输入输出重定向到超级终端*/
if((consoleFd=open("/tyCo/0",O_RDWR,0))==ERROR)
logMsg("open /tyCo/0 error! \n",0,0,0,0,0,0);
(void)ioctl(consoleFd,FIOBAUDRATE,9600);
(void)ioctl(consoleFd,FIOSETOPTIONS,OPT_TERMINAL&~OPT_ECHO);
(void)ioctl(consoleFd,FIOWFLUSH,0);
(void)ioctl(consoleFd,FIORFLUSH,0);
(2) VxWorks中的重定向
在BootRom中将标准输入输出已经定向到串口,但是在VxWorks中,当BootRom起来将VxWorks引 导后,将执行权交给了VxWorks,而此时VxWorks会将BootRom中对硬件初始化的过程重新初始化,故其定向会重新按照缺省方式定向到PC console,标准VGA输出和键盘输入。那么又怎么将其定向回串口呢?
打开target\config\comps\src\usrPcConsole.c文件
在其代码中也同样可以看到其定向过程,那么我们也可以按照BootRom的方式将串口打开并定向。
(3) VxWorks5.5中的输入输出定向
在VxWorks5.5中,已经将其标准输入输出直接定向到串口,并且其标准输入输出更简单,直接通过target\config\bspName\config.h文件中的宏定义就可以实现。怎么样切换回PC console的输入输出模式呢?
在target\config\bspName\config.h文件中,可以找到如下定义:
#undef INCLUDE_PC_CONSOLE /* PC keyboard and VGA console */
#ifdef INCLUDE_PC_CONSOLE
# define PC_CONSOLE (0) /* console number */
# define N_VIRTUAL_CONSOLES (2) /* shell / application */
#endif /* INCLUDE_PC_CONSOLE */
/* PS/2 101-key default keyboard type (use PC_XT_83_KBD for 83-key) */
#define PC_KBD_TYPE (PC_PS2_101_KBD)
从上可以看出,缺省情况下,宏INCLUDE_PC_CONSOLE是关闭的,所以我们在制作 BootRom后,启动时在显示器上会出现如下的输出:
并且此时会停在这里不动,感觉好象是系统不能启动,其实,系统已经启动起来了,并且其打印信息已经输出到串口,如果你插上串口线的话,可以从超级终端看到打印输出的。
定义宏INCLUDE_PC_CONSOLE后,同时也定义了PC_CONSOLE和键盘类型,这样就可以通过键盘接受标准输入,通过显示器有标准输出。
实际开发中的应用
在实际产品开发中,用户可能会开发适合自己风格的用户操作接口,包括Telnet、console等,console即串口的超级终端输入输出,按照以上方法实现其定向,但是Telnet时可能就需要随时将标准输入输出定向到打开的相应的Telnet socket。WindRiver公司有一套制作用户接口(CLI)工具——RapidControl,利用此工具可以很快开发出类CISCO风格的Telnet、console。此工具提供了将输入输出定向到Telnet socket的API 函数,但是有很多VxWorks的系统函数如ping、inetstatShow、ipstatShow其输出还是标准的printf,故在Telnet 中调用这些函数时,就需要随时实行标准输入输出的定向。
假如某Telnet打开的socket为sock:
ioGlobalStdSet(STD_OUT,sock);
ioGlobalStdSet(STD_IN,sock);
ioGlobalStdSet(STD_ERR,sock);
ipstatShow();
ioGlobalStdSet(STD_OUT,consoleFd);
ioGlobalStdSet(STD_IN,consoleFd);
ioGlobalStdSet(STD_ERR,consoleFd);
先将输入输出定向到sock,调用相关的函数,再将输入输出定向回来,如果不定向回来的话,那么console和别的Telnet就无法操作了。
添加组件 vxBus subsystem show routines
如果找到,二者结合成一个instance,否则在vxBusShow里可以看到一个orphan。使用vxBusShow可以比较清晰的看到driver列表和device列表以及orphan列表
getcpuusage命令
ifAddSet "motetsec0 192.168.5.100 up"
ifMaskSet "motetsec0 255.255.255.0 up"
ifConfig "motetsec0 192.168.5.100 up"
ifConfig "motetsec0 lladdr 192.168.5.100 up"
uartShow
vxTypesOld.h
e_vxTypesOld.h
需要重启下workbench
nmpentium default/vxWorks | grep wrsampleRegister
timexN delay,100
int bb()
{
char name[32];
int ip = 0;
char ipadd[15];
char *p;
struct in_addr iaddr;
if (gethostname(name, 30) == ERROR) //This routine gets the target machine's symbolic name, which can be used for identification
{
fprintf(stderr, "Call gethostname failed!\n");
return 0;
}
if ((ip = hostGetByName(name)) == ERROR) //这个数怎么变x.x.x.x 例如192.168.0.50
{
fprintf(stderr, "Call hostGetByName failed!\n");
return 0;
}
iaddr.s_addr = ip;
sprintf(ipadd, "%s", inet_ntoa(iaddr));
p = inet_ntoa(iaddr);
printf("%s\n%d\n %s\n", name, ip, ipadd);
printf("%s\n", p);
}
添加组件 vxBus subsystem show routines
gethostName 得到名称为target name
This routine gets the target machine's symbolic name, which can be used for identification
最后处理得到的ip为 inet on ethernet
1. 新建一个“Downloadable Kernel Module Project”工程
2. 选择对应的硬件环境,此处选择“MIPSI64gnule_SMP”
3. 选择需要编译生成的库形式,Linker对应生成动态库.out,Librarian对应生成静态库.a
4. 编译成成对应库文件(此处以静态库为例)
5. 新建一个image工程,点击右键的properties,选择build properties
6. 点击build properties,选择build macros选项卡,该选项下有两栏需特别注意,一个是EXTRA_MODULES,一个是LIBS,在image工程中我们要链接MODULE工程编译生成的库文件,需要添加在EXTRA_MODULES栏中,可以在其中链接诸如.o、 .a等文件。但是在LIBS中链接这类a文件,会编译报错,至于为何报错,以及这两者有啥区别,有待日后研究
New Wind River Workbench Project ---> 类型为static Kernel Library ,不能选择vxwork6.x project 否则看不到static Kernel Library 类型引用为 编译类型需要在工程创建后更改
image:
启动参数中的脚本优先于usrAppinit执行.若需要在usrAppInit里面执行,则需要收到调用
usrStartupScript("/tffs0/start_opensca")函数使用?
启动目标机,在bootrom引导vxworks时,指定startup script参数,如:
boot device : cpm
unit number : 0
processor number : 0
host name : chenqi
file name : vxWorks
inet on ethernet (e) : 192.168.0.200
host inet (h) : 192.168.0.118
user (u) : target
ftp password (pw) : target
flags (f) : 0x0
target name (tn) : 850pc
startup script (s) : myscript.txt
如果一切正常,vxworks启动完毕之后,会有:
Executing startup script myscript.txt ...
printf("hello ")
hello
出现下面情况
ipAttach(0, "motetsec")
C interp: unknown symbol name 'ipAttach'
需要添加Attach END to IPv4
STATUS get_mac(char *ifName, int ifUnit)
{
END_OBJ *pEnd;
UINT8 *pData = NULL;
int i = 0;
STATUS rval = 0;
pData = (UINT8 *) malloc(MAC_ADRS_LEN);
pEnd = endFindByName(ifName, ifUnit);
if (pEnd == NULL) {
perror("pEnd is null \n");
return ERROR;
}
rval = muxIoctl(pEnd, EIOCGADDR, pData);
for (i = 0; i < MAC_ADRS_LEN; i++) {
printf("%02x:", *(pData + i));
}
return rval;
}
step one: tffsDevFormat(0,0)---normal step two: usrTffsConfig(0,0,"/tffs0")
usrTffsConfig (1, 0, "/tffs1");
-> cd "/tffs0"
cd: error = 0x16.·
value = -1 = 0xffffffff
set three:dosfsDiskFormat("/tffs0")
主要是建立ip协议栈与mux接口之间的关系?
主要是建立ip协议栈与mux接口之间的关系?
The makefile provides a mechanism that allows you to use the local copy instead
of the common version. The following macros designate a private copy of the
related files:
For example, to use a private version of usrConfig.c, set the macro USRCONFIG to
usrConfig.c in Makefile as follows:
USRCONFIG = usrConfig.c
target.ref uses the apigen markup language
When building a VxWorks image, many compile-time macros are expanded, and
it is sometimes difficult to know what the actual numeric values of these macros
are and which branch of conditionally compiled code is being used. The bootrom
code, in particular, contains many conditional compilations. One way to find this
information is to retrieve the post-processed compiler output.
To retrieve the post-processor output for a given object module, use the following
command:
make ADDED_CFLAGS=-E file.o > file.i
Next, remove all of the lines starting with # and all blank lines
示例为根据等待任务名为"taskIde"结束
if(taskIdVerify(taskNameToId("taskIde")) != ERROR)
{
taskWait(taskNameToId("taskIde"),sysClkRateGet()*2);
}
*.mk
_USER_CFLAGS = -I $(BSP_DIR)/net/mii -I $(BSP_DIR)/appDrivers -I $(BSP_DIR)/lib_utils -I $(BSP_DIR)/SRIO -I $(BSP_DIR)/net -I $(BSP_DIR)/mv88e6xxx -I $(BSP_DIR)/net -I $(BSP_DIR)/net/linux_mv88e6xxx -I $(BSP_DIR)/net/gtLib
.wpj
BUILD_default_MACRO__USER_CFLAGS
-I \
$(BSP_DIR)/net/mii \
-I \
$(BSP_DIR)/appDrivers \
-I \
$(BSP_DIR)/lib_utils \
-I \
$(BSP_DIR)/SRIO \
-I \
$(BSP_DIR)/net \
-I \
$(BSP_DIR)/mv88e6xxx \
-I \
$(BSP_DIR)/net \
-I \
$(BSP_DIR)/net/linux_mv88e6xxx \
-I \
$(BSP_DIR)/net/gtLib
关于出现找不到 nfsmaxPath符号表示因为,未定制nfs 客户端与核心组件
IMPORT int nfsMaxPath; /* max. length of file path */
关于出现找不到 nfsmaxPath符号表示因为,未定制nfs 客户端与核心组件
windows: ping -s 192.168.5.84 192.168.5.81
vxworks : ping "-S 192.168.5.82 192.168.5.84" (-I 可指定网口名)
修改启动参数
flags =0x8
解决方案:
- In operating system components / kernel components / : you must include the component "Allow 32-bits branches to handlers"
- In operating system components / real time process components / : you must include the component "shared data region support in RTPs or kernel"
ramDrv 需要添加组件ram disk driver 和xbd ram disk driver
然后在代码中自己添加内存文件系统
BLK_DEV *pBlkDev1;
pBlkDev1 = ramDevCreate((char *)sysMemTop(), 512, 32768, 32768, 0);
xbdBlkDevCreateSync(pBlkDev1, "/ram");
dosFsVolFormat("/ram:0", DOS_OPT_BLANK, NULL);
BLK_DEV *pBlkDev2;
pBlkDev2 = ramDevCreate((char *)(sysMemTop() + 0x1000000), 512, 32768, 32768, 0);
xbdBlkDevCreateSync(pBlkDev1, "/ram1");
dosFsVolFormat("/ram1:0", DOS_OPT_BLANK, NULL);
MEM文件系统:添加memLib 需要添加组件MEM disk driver
memDrv 即可flash也可内存,ramDrv只能用途内存
DOS_OPT_BLANK = 2
总结:
NandFlash页的概念
- page: 一个page大小为2K + 64bytes, 如上图所示, 其中的64bytes是所在页的infomation, 记录着此页的使用情况, 比如剩余存空间等
- >block: 一个block由64个页组成, 一个nandflash芯片由2k个block组成,算算就知道,一个nandflash芯片一共能存储256M的数据
#ifdef MHAL_ETH_DEBUG_ON
#define LOG_LVL 7
#define WARN_LVL 3
#define ERROR_LVL 1
#define NONE_LVL 0
LOCAL int mhalEthernetDgbLvl = NONE_LVL;
#define MHAL_ETH_DBG_MSG(level, fmt, a1, a2, a3, a4, a5, a6) \
do{ \
if(mhalEthernetDgbLvl >= level) \
logMsg(fmt,(int)(a1),(int)(a2),(int)(a3),\
(int)(a4),(int)(a5),(int)(a6)); \
}while ((0))
#else
#define MHAL_ETH_DBG_MSG(level,fmt,a1,a2,a3,a4,a5,a6)
#endif /* MHAL_ETH_DEBUG_ON */
当前原因是因为配置文件中包含了WRLoad组件,去掉即可。
一些标志位的集合,每个标志代表一个特殊的选项。这些标志定义如下:
- 0x01 = 即使processor number为0,也不要激活系统控制器。(这个其实是由使用的板子解释的,所以应参考目标板子的资料)
- 0x02 = 载入所有VxWorks符号表,而不只是全局部分。
- 0x04 = 不要自动引导
- 0x08 = 快速自动引导,也就是自动引导前等的时间短一些。
- 0x20 = 禁用安全登录。
- 0x80 = 用TFTP(而不是FTP)来引导。
- 0x400 = 调试模式。
workbench怎么生成带debug调试信息的bootrom
ADDED_CFLAGS += -g -O
如何判断elf文件是否包含调试信息
测试发现static kernel library 链接到kernel image 时只会链接使用到的函数文件
所以采用Relinkable kernel Module,其实就是DKM工程
eieio, sync 和 isync 是上下文同步指令。
上下文同步指的是:处理器内核包含着多个独立的执行单元,所以它能够并行的执行多个指令并且是乱序的。上下文同步指令用于需要严格秩序的地方,进行强制严格的指令顺序。
eieio代表“强制按顺序执行IO”。在执行过程中,加载/存储单元等待前一个访问结束之后再开始运行加载/存储指令。eieio的目的就是为了防止执行过程中的随意加载和存储。在执行FIFO数据的读写变化时这可能是可取的。
isync代表“指令同步”。这个指令等待所有的指令完成并放弃预读取指令,导致后续的指令需要从内存中重新读取。isync是上下文同步,它保证所有先前指令都到位并且刷新指令序列(这意味着指令序列中的所有指令需要被重新读取)。
sync代表着内存同步指令。它延迟所有后续指令的执行直到先前指令完成,并且不会再产生异常以及直到先前的内存访问完全执行完毕;sync操作不会广播到总线接口。此外,先前指令发起的所有加载和存储高速缓存/总线活动完成。
- sp function,[arg1],...,[arg9] - 启动任务,最多接受9个参数,默认的优先级100、堆栈20000字节
- period n,function,[arg1],...,[arg8] - 创建一个周期调用function的任务,周期为n秒,最多接受8个参数
- repeat m,function,[arg1],...,[arg8] - 创建一个反复调用function的任务,调用次数为m,m=0时永久调用,最多也是8个参数
- ts tidX -挂起任务
- tr tidX -恢复挂起的任务
- td tidX -删除任务
- i tidX -显示任务基本信息,参数为0时显示全部任务
- ti tidX -显示任务详细信息,包括寄存器、堆栈等
- tt tidX -显示任务的函数调用关系
- checkStack tidX -显示任务堆栈使用的历史统计,参数为0时显示全部任务
[其中tidX可以为任务ID 也可以为任务名]
lkup ["string"] -在系统符号表中查找并列出含有"string"字符的函数及全局变量,有两个特殊参数:
0,给出符号表统计;""(空字符串),列出全部符号
lkAddr addr -显示addr地址附近的符号表
l addr,[n] -显示addr地址开始的n条指令的反汇编,n省略时默认为10条指令
h [n] -n为0时列出最近执行的shell命令,默认20条;n非0时,设定shell记录的历史命令的数目
d [addr,[number],[width]]
-显示addr地址开始的number个单元的内容,width定制每个单元的宽度,可以是1、2、4、8
m addr,[width] -按width宽度修改addr地址的内容,width可以是1、2、4、8
memShow 1 -显示系统分区上空闲和已分配空间的总数等
printErrno value -打印系统定义的错误码的宏
1).命令行启动rtpsp /ata0a/rtptest.vxe
2).应用程序里面启动
constchar*argv[]={“/ata0a/测试.vxe“,NULL}
rtpSpawn(argv[0],argv,NULL,100,0x10000,0,0)
1).命令行启动rtpsp /ata0a/rtptest.vxe
2).应用程序里面启动
使用 shConfig 命令修改环境变量:
shConfig(char *config) -参数为NULL时,显示当前Shell的配置参数,否则设置其参数
SH_GET_TASK_IO
为调用函数设置I/O重定向。ON:重定向到WindSh;OFF:I/O显示到目标机控制台。
LD_PATH
为模块设置搜索路径用“”隔开。例如ld 命令提交后Shell搜寻模块的路径顺序为首先在当前目录然后到LD_PATH设置的路径。
LD_SEND_MODULES
设置load模式。
以下3个用不到
LD_CALL_XTORS
LD_COMMON_MATCH_ALL
DSM_HEX_MOD
taskSwitchHookShow
ld < test.out 加载test.out模块到系统
unld id 卸载模块
- cd 改变工作目录
- ls 列出工作目录下的文件
- pwd 显示当前工作目录
- copy 拷贝文件 copy “host:cnset.cfg”“/HDisk/cnset.cfg”
- remove 删除文件 remove “/HDisk/trace/error.log”
- rename 更改文件名称
释放shell内动态分配的字符指针。参数为0,则打印当前所有字符指针;参数为-1,则释放所有指针
不过在shell中直接声明的字符指针,应该用free()来释放
- 写.bat脚本,右键运行
- 添加到POST_BUILD_RULE
> cd "host:"
BOOT命令,启动时使用,用于查看和修改启动参数等操作
- p,打印配置
- c, 修改配置
- ?, 帮助信息
- @,加载内核
- Ctrl+X,重新启动
实际flush()/invalidate()函数有如下两组,功能相同稍有区别:
组1:CACHE_DMA_FLUSH()函数和CACHE_DMA_INVALIDATE()函数
组2:cache Flush()函数和cacheInvalidate()函数
target/src/hwif/xxx 下
xxx.c 和 xxx.mk --- 源文件和makefile文件
target/src/hwif/h/xxx 下
xxx.h -- 头文件
target/config/comps/vxworks下
xxx.cdf -- cdf文件用于被workbench识别
target/config/comps/src/hwif下
xxx.dc xxx.dr - dc dr用于命令行编译
e.g.: 新加一个串口驱动
- vxbUccSio.c
- vxbUccSio.h
- vxbUccSio.mk
- vxbUccSio.dc
- vxbUccSio.dr
- 40vxbUccSio.cdf
chkdsk() & hrfsChkDsk() 和 dosFsShow()
STATUS dosFsShow
(
void * pDevName,
u_int level
)
STATUS chkdsk
(
const char * pDevName,
u_int repairLevel,
u_int verbose
)
STATUS hrfsChkDsk
(
char * path,
int verbLevel,
int flags
)
# define INCLUDE_ISR_OBJECTS
# define INCLUDE_ISR_SHOW
# define INCLUDE_ISR_DEFER
#define INCLUDE_EDR_SHOW
#define INCLUDE_EDR_ERRLOG
#define INCLUDE_EDR_PM
#define INCLUDE_EDR_SYSDBG_FLAG
status = symFindByName(sysSymTbl, "test", (char *)&task_entry, ptype);
task_entry();
-> sysExcMsg sysExcMsg = 0x1d197f8: value = 17152 = 0x4300
-> d 0x4300
intLock():使中断禁止
intUnlock():开中断
可以用intLock/intUnlock提供最高级别的互斥机制以保护临界区域不被打断解决方法:移除-ansi开关。可是怎么移除呢?对许多对编译器不太了解的人可能看了FAQ了不知道怎么办。
下面具体讲解:
在vxWorks的工程里有build这个选项,字体变黑的就是你选的编译类型以default为例,双击default(默认的),在c/c++compiler和assember里将-ansi去掉,然后再OK!
中断是由硬件触发,软件的作用只是将中断服务例程(ISP)与中断事件连接起来
1. 使能中断,函数intEnable()
2. 用intConnect()登记中断号,和相应的中断例程ISR这样一旦有中断发生,系统自动跳转到相应位置执行ISR