前段时间抽空做了vxWorks7.0下的基于zynq的boot程序,在此做个总结。

vxworks7.0支持三种不同的boot程序:第一种uboot,第二种vxworks6.9.x以上的bootloader,第三种bootapp,关于uboot的创建方法在前面的博文中已经提到过,bootloader6.9的话,因为我不在使用6.9的版本,所以在此也就不做介绍,今天我们来谈一谈vxworks7.0下bootapp的创建方法。

首先,创建VSB工程,在创建VSB工程时一定要选择up类型创建,具体的创建方法,做过vxworks7.0的都会,在这里就不多做介绍了。

其次创建VIP工程,使用-profile PROFILE_BOOTAPP属性创建VIP工程,在VIP工程中添加组件INCLUDE_STANDALONE_DTB,使用嵌入式的vxWorks,让设备树编译到vxWorks中去。切记不能包含组件INCLUDE_PATCH_STANDALONE_DTB

接着增加boot参数的存储配置,如果有独立的基于IO系统的eeprom专门用于存储boot参数,包含组件INCLUDE_BOOTAPP_NVRAM_SUPPORT,设置其属性值:


prj vip parameter set BOOTAPP_GENERIC_NVRAM_NAME \"/eeprom/0\"
prj vip parameter set BOOTAPP_GENERIC_NVRAM_OFFSET 0x0
prj vip parameter set BOOTAPP_GENERIC_NVRAM_SIZE 0x100

其中BOOTAPP_GENERIC_NVRAM_NAME必须是你devs看到的IO系统的flash设备名称。其他参数是flash设备的大小和偏移地址。

在这里我使用的是S25FL265S的QSPIflash,总大小为0x2000000,其中前0x800000为boot和设备的一些配置参数,其余的用于挂接文件系统,存放系统的启动镜像文件,所以在0x800000-0x10000位置存储boot参数,用于设备启动时参数的修改,修改bsp文件


void bootAppSaveBootLine
    (
    char *  buf,    /* source buffer to save */
    int     len     /* length of buffer to save */
    )
    {
#ifdef INCLUDE_BOOTAPP_NVRAM_SUPPORT
    if (bootAppNvSet == 0 || ERROR == bootAppNvSet (buf, len, 0))
        {
        bootAppPrintf("\nNOTE: Saving Bootline to NVRAM failed\n" ,0,0,0,0,0,0);
        }
#else
    if (sysNvRamSet (buf, len, 0) == OK)
       {
       	return;
       }
	bootAppPrintf("\nNOTE: Bootline obtained from DTB and needn't be written"
                  " back\n",0,0,0,0,0,0);
#endif /* INCLUDE_BOOTAPP_NVRAM_SUPPORT */
    }

增加boot启动时的参数获取函数sysNvRamSet(),同时在bootapp工程中增函数


STATUS sysNvRamSet
    (
    char *  string,         /* string to be copied into non-volatile RAM */
    int     strLen,         /* maximum number of bytes to copy           */
    int     offset          /* byte offset into non-volatile RAM         */
    )
{
	STATUS  retVal = ERROR;
	UINT8 * ppbuf[1];
	int     offsetRel = offset + NV_BOOT_OFFSET;
	VXB_DEV_ID pFlashId;
	SPI_FLASH_DEV *     pDrvCtrl    = NULL;
 
    bootAppPrintf ("enter to nvRam Flashwrite\n", 0, 0, 0, 0, 0, 0);
    if ((offsetRel < 0) || (strLen < 0) ||
        ((offsetRel + strLen) > NV_RAM_SIZE))
    {
        NVRAM_DBG_MSG ("[0x%x,0x%x] is out of range(0x%x)\n",
                       offsetRel, offsetRel + strLen - 1, NV_RAM_SIZE,
                       0, 0, 0);
        return (ERROR);
    }
 
    pFlashId = vxbDevAcquireByName(NV_RAM_FLASH_NAME,NV_RAM_FLASH_UNIT);
    if(pFlashId == NULL)
    {
    	NVRAM_DBG_MSG ("not find flash dev\n",0, 0 , 0, 0, 0, 0);
    	return (ERROR);
    }
    pDrvCtrl = vxbDevSoftcGet(pFlashId);
    if(!pDrvCtrl)
    {
    	NVRAM_DBG_MSG ("not find flash dev driver\n",0, 0 , 0, 0, 0, 0);
    	return (ERROR);
    }
    //从FLASH中读出参数,进行比较,如果没有变化,直接返回成功
    ppbuf[0] = (UINT8 *) pBlkBuf;
    NVRAM_DBG_MSG ("compare boot param\n",0, 0 , 0, 0, 0, 0);
	if((getFlashReadFun()(pDrvCtrl,offsetRel,strLen,ppbuf[0]) == OK )&& 
			(bcmp ((char *) (pBlkBuf), string, strLen) == 0))
		goto nvRamSetOk;
 
	NVRAM_DBG_MSG ("start erase boot sector[%d],secsum[%d]\n",offsetRel, 1 , 0, 0, 0, 0);
	if(getFlashSectorEraseFun()(pDrvCtrl,offsetRel,1)!= OK)
	{
		NVRAM_DBG_MSG ("flash erase sector[%08x]failed\n",offsetRel, 0 , 0, 0, 0, 0);
		return ERROR;
	}
    
    /* copy data to buffer and write to Flash */
 
   bcopy (string, (char *) (pBlkBuf), strLen);
   NVRAM_DBG_MSG ("start write boot param[%s]\n",ppbuf[0], 0 , 0, 0, 0, 0);
   if(getFlashWriteFun()(pDrvCtrl,offsetRel,strLen,ppbuf[0]) != OK)
   {
	   NVRAM_DBG_MSG ("flash erase sector[%08x] context[%s]..failed\n",offsetRel, ppbuf , 0, 0, 0, 0);
	  return ERROR; 
   }
 
nvRamSetOk:
    retVal = OK;
    
    return (retVal);
}

此函数用于设置boot参数到flash位置0x800000-0x10000除,boot参数大小为255,读取boot参数方法也一样,修改下列函数


void bootAppLoadBootLine (void)
    {
#ifdef INCLUDE_BOOTAPP_NVRAM_SUPPORT
    if (bootAppNvGet &&
        (bootAppNvGet ((char *)BOOT_LINE_ADRS, BOOT_LINE_SIZE, 0) == OK) &&
        (*((char *)(BOOT_LINE_ADRS)) != EOS) &&
        (*((char *)(BOOT_LINE_ADRS)) != (char) -1))
        {
        return;
        }
    bootAppPrintf("\nNOTE: load Bootline from NVRAM failed\n" ,0,0,0,0,0,0);
#endif /* INCLUDE_BOOTAPP_NVRAM_SUPPORT */
 
    if (sysNvRamGet ((char *)BOOT_LINE_ADRS, BOOT_LINE_SIZE, 0) == OK)
    {
    	return;
    }
    if (vxFdtBootargsGet ((char *)BOOT_LINE_ADRS, BOOT_LINE_SIZE) != OK)
        {
#ifndef _WRS_ARCH_IS_SIMULATOR
        strncpy ((char *)BOOT_LINE_ADRS, DEFAULT_BOOT_LINE, BOOT_LINE_SIZE);
#endif /* _WRS_ARCH_IS_SIMULATOR */
        }
    }

在bootapp中增加函数sysNvRamGet()实现


STATUS sysNvRamGet
    (
    char *  string,         /* where to copy non-volatile RAM    */
    int     strLen,         /* maximum number of bytes to copy   */
    int     offset          /* byte offset into non-volatile RAM */
    )
{
	STATUS  retVal = ERROR;
	UINT8 * ppbuf[1];
	int     offsetRel = offset + NV_BOOT_OFFSET; 
	VXB_DEV_ID pFlashId;
	SPI_FLASH_DEV *     pDrvCtrl    = NULL;
	
	bootAppPrintf ("enter to nvRam Flashread\n", 0, 0, 0, 0, 0, 0);
	
	if ((offsetRel < 0) || (strLen < 0) || ((offsetRel + strLen) > NV_RAM_SIZE))
	{
		NVRAM_DBG_MSG ("[0x%x,0x%x] is out of range(0x%x)\n",
						offsetRel, offsetRel + strLen - 1, NV_RAM_SIZE,
						0, 0, 0);
		return (ERROR);
	}
        
	pFlashId = vxbDevAcquireByName(NV_RAM_FLASH_NAME,NV_RAM_FLASH_UNIT);
	if(pFlashId == NULL)
	{
		NVRAM_DBG_MSG ("not find flash dev\n",0, 0 , 0, 0, 0, 0);
		return (ERROR);
	}
	pDrvCtrl = vxbDevSoftcGet(pFlashId);
	if(!pDrvCtrl)
	{
		NVRAM_DBG_MSG ("not find flash dev driver\n",0, 0 , 0, 0, 0, 0);
		return (ERROR);
	}
 
	if (strLen == 0)
	{
		string [strLen] = EOS;
		return OK;
	}
 
    ppbuf[0] = (UINT8 *) string;
	
	if(getFlashReadFun()(pDrvCtrl,offsetRel,strLen,ppbuf[0]) == OK)
		retVal = OK;
	
    return (retVal);
}

接下来修改bootapp的内核配置,增加组件

Zynq VxWorks 7.0

在内核配置中增加组件


INCLUDE_BOOT_FILESYSTEM,
INCLUDE_TFFS_TL,
INCLUDE_TFFS,
INCLUDE_TL_FTL,
INCLUDE_TFFS_MOUNT,
INCLUDE_MTD_VXBFLASH

修改参数


prj vip parameter setstring VXBFLASH_CFG_STR "$spiflash0#0:0x0,0x2000000,0x800000,rfa0"

在此32Mflash预留8M用作BOOT和一些系统参数,修改完成后编译,生成vxWorks

生成BOOT.bin

1、将上面生成的vxworks拷贝到指定文件夹,并重命名为bootapp.elf

2、启动xilinx的sdk,打开create_boot_image工具

Zynq VxWorks 7.0

选择输出文件夹,然后点击add,线增加fsbl,然后增加系统bit文件,最后增加bootapp.elf,切记顺序不能出错。

Zynq VxWorks 7.0

生成BOOT.bin,烧录到flash中,选择从flash启动

Zynq VxWorks 7.0

至此文件i系统和网络启动正常。

vxWorks7.0系统镜像在启动时,可能从网口加载可以成功,但是从文件系统加载失败,解决办法如下:

打开workbeach4.0,打开工程目录,打开development shell,进入到vxWorks系统镜像目录

输入image-tag tag vxWorks,回车,让vxWorks7.0镜像打上标记,然后传进文件系统启动

Zynq VxWorks 7.0

启动时可能找不到网口,这时如果启动方式为文件系统启动,boot参数的other选项应该配置为gem0如下所示:

Zynq VxWorks 7.0

不过因为这种启动方式使用的是嵌入式的设备树,所以系统镜像比较大,这是这种启动方式的唯一缺点,可根据自己的需要选择相应的boot方式。