S3C2450自动升级
在BSP包中,有两个bootloader文件夹,一个命名为bootloader,另一个命名为bootloader_update。Bootloader文件夹用于USB下载,调试用,bootloader_update用于生产,自动升级用。下面重点介绍bootloader_update文件夹。
Bootloader_update文件夹下有四个文件夹,分别是BLCOMMON,Eboot_boot,FAT_LIB以及IROM_SD_TOOL。BLCOMMON文件夹编译后生成oal_blcommon.lib文件,供Eboot_boot调用。FAT_LIB文件夹里面包含三个静态库文件FAT_LIB.lib,HSMMCEBOOT_LIB.lib以及SDREAD_UPDATE.lib。这些静态库封装了一些用于升级的函数。Eboot_boot文件夹编译后将会产生生产用的Eboot.bin文件,该文件即能够启动系统,也能够通过硬件平台的按键控制,实现自动升级。IROM_SD_TOOL文件夹编译后,会将前面的Eboot.bin文件封装成SD卡识别的程序,最终生成IROM_SD_EBOOT.nb0。通过三星提供的IROM_Fusing_Tool工具,将该文件烧到SD卡后,2450平台就能够实现从SD卡启动了。当然前提是硬件本身要设置跳线成SD卡启动。
主程序中(Eboot_boot文件夹)定义了三个重要的变量:AUTO_UPDATE_FROM_SD;
ERASE_ALL_FLASH_BLOCKS;
SHOW_UPDATE_LOGO。
当AUTO_UPDATE_FROM_SD为真时,Eboot将会进入升级程序,为假时将引导flash中的NK,启动系统。
当ERASE_ALL_FLASH_BLOCKS为真时,Eboot将会格式化flash,然后依次升级block0.nb0,eboot.bin,nk.bin,随后启动系统。
当SHOW_UPDATE_LOGO为真时,LCD上将会出现升级文件的提示,否则显示开机LOGO。
其中AUTO_UPDATE_FROM_SD标志位通过硬件平台的按键判断,当拨动电源键后在两秒之内回拨到LOCK位置,Eboot将识别到该LOCK标志,这时将AUTO_UPDATE_FROM_SD置高,程序进入升级状态。
ERASE_ALL_FLASH_BLOCKS标志位通过从SD卡中的update.txt文件中读取。
AUTO_UPDATE_FROM_SD的相关代码如下:
if(1 == UPDATA_ALL_IMAGE)
{
AUTO_UPDATE_FROM_SD =TRUE;
ERASE_ALL_FLASH_BLOCKS =TRUE;
SHOW_UPDATE_LOGO = TRUE;
}
else if( _FAT_Boot_ReadFile(_BOOT_TYPE_SD_BIN, _UPDATE_FILE_DETECT) ||auto_updatekey_isPressed() )
{
//自动升级健按下进行自动升级
AUTO_UPDATE_FROM_SD=TRUE;
}
else
{
AUTO_UPDATE_FROM_SD = FALSE;
}
其中_FAT_Boot_ReadFile()函数用于从SD卡中读取_UPDATE_FILE_DETECT文件,该字符串在最前面有如下定义:
#define _UPDATE_FILE_DETECT "DETECT BIN"
auto_updatekey_isPressed()函数用于检测拍照键是否按下,从这里可以看出,如果SD卡中存在detect.bin文件,则升级时不用再按住拍照键了。如果没有则必须按住拍照键。
Flash格式化的程序如下:
if(1)// format flash.
{
//ADDED BY ZHOUPENG FOR TEST
ReadDeviceSerialNumber(Serial_Block_Number,pBuf8);
ReadDeviceSerialNumber(Smit_Device_Serial_Block_Number,pBuf9);
OALMSG(TRUE, (TEXT(" ++Format FIL (Erase All Blocks)/r/n")));
if (VFL_Close() != VFL_SUCCESS)
{
OALMSG(TRUE, (TEXT("[ERR] VFL_Close() Failure/r/n")));
}
if (WMR_Format_FIL() == FALSE32)
{
OALMSG(TRUE, (TEXT("[ERR] WMR_Format_FIL() Failure/r/n")));
}
if (WMR_Format_VFL() == FALSE32)
{
OALMSG(TRUE, (TEXT("[ERR] WMR_Format_VFL() Failure/r/n")));
}
if (WMR_Format_FTL() == FALSE32)
{
OALMSG(TRUE, (TEXT("[ERR] WMR_Format_FTL() Failure/r/n")));
}
OALMSG(TRUE, (TEXT("[INF] You can not use VFL before Format VFL/r/n")));
OALMSG(TRUE, (TEXT(" --Format FIL (Erase All Blocks)/r/n")));
WriteDeviceSerialNumber(Serial_Block_Number,pBuf8);
WriteDeviceSerialNumber(Smit_Device_Serial_Block_Number,pBuf9);
}
下载映像的函数如下:
static BOOL DownloadImage (LPDWORD pdwImageStart, LPDWORD pdwImageLength, LPDWORD pdwLaunchAddr)
{
BYTE hdr[BL_HDRSIG_SIZE];
DWORD dwRecLen, dwRecChk, dwRecAddr;
BOOL fIsFlash = FALSE;
LPBYTE lpDest = NULL;
int nPkgNum = 0;
BYTE nNumDownloadFiles = 1;
DWORD dwImageStart = 0;
DWORD dwImageLength = 0;
RegionInfo *pCurDownloadFile;
int i;
*pdwImageStart = *pdwImageLength = *pdwLaunchAddr = 0;
g_DownloadManifest.dwNumRegions = 0 ;
for( i = 0 ; i < BL_MAX_BIN_REGIONS ; i++)
{
g_DownloadManifest.Region[i].dwRegionStart = 0;
g_DownloadManifest.Region[i].dwRegionLength = 0;
g_DownloadManifest.Region[i].szFileName[0] = '/0';
}
do
{
// 将*.bin文件的前7个字节数据读入hdr(header)数组
if (!OEMReadData (BL_HDRSIG_SIZE, hdr))
{
EdbgOutputDebugString ("/r/nUnable to read image signature./r/n");
HALT (BLERR_MAGIC);
return (FALSE);
}
// An N000FF packet is manufactured by Platform Builder when we're
// downloading multiple files or when we're downloading a .nb0 file.
if (!memcmp (hdr, "N000FF/x0A", BL_HDRSIG_SIZE))//比较数据相等时memcmp返回0
{
// read the packet checksum.
//
if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk))
{
EdbgOutputDebugString("/r/nUnable to read download manifest checksum./r/n");
HALT (BLERR_MAGIC);
return (FALSE);
}
// read BIN region descriptions (start address and length).
//
if (!OEMReadData (sizeof (DWORD), (LPBYTE) &g_DownloadManifest.dwNumRegions) ||
!OEMReadData ((g_DownloadManifest.dwNumRegions * sizeof(RegionInfo)), (LPBYTE) &g_DownloadManifest.Region[0]))
{
EdbgOutputDebugString("/r/nUnable to read download manifest information./r/n");
HALT (BLERR_MAGIC);
return (FALSE);
}
// verify the packet checksum.
if (!VerifyChecksum((g_DownloadManifest.dwNumRegions * sizeof(RegionInfo)), (LPBYTE) &g_DownloadManifest.Region[0], dwRecChk))
{
EdbgOutputDebugString ("/r/nDownload manifest packet failed checksum verification./r/n");
HALT (BLERR_CHECKSUM);
return (FALSE);
}
if (g_pOEMMultiBINNotify)
{
g_pOEMMultiBINNotify((PDownloadManifest)&g_DownloadManifest);
}
// look for next download...
nNumDownloadFiles = (BYTE)(g_DownloadManifest.dwNumRegions + 1); // +1 to account for this packet.
continue;
}
// Is this an old X000FF multi-bin packet header? It's no longer supported.
else if (!memcmp (hdr, "X000FF/x0A", BL_HDRSIG_SIZE))
{
EdbgOutputDebugString ("ERROR: The X000FF packet is an old-style multi-bin download manifest and it's no longer supported. /r/nPlease update your Platform Builder installation in you want to download multiple files./r/n");
HALT (BLERR_MAGIC);
return (FALSE);
}
// Is this a standard bin image? Check for the usual bin file signature.
else if (!memcmp (hdr, "B000FF/x0A", BL_HDRSIG_SIZE))//lqm:下载xip.bin,nk.bin,eboot.bin时在这里执行
{
g_bBINDownload = TRUE;
if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageStart)//读取*.bin前7个头字节后的一个DWORD到dwImageStart。*.bin记录了其映像起始地址
|| !OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageLength))//读取上面接着的一个DWORD到dwImageLength。*.bin记录了其映像长度
{
EdbgOutputDebugString ("Unable to read image start/length/r/n");
HALT (BLERR_MAGIC);
return (FALSE);
}
}
// If the header signature isn't recognized, we'll assume the
// download file is a raw .nb0 file.
//
else
{
g_bBINDownload = FALSE;
}
if (!g_DownloadManifest.dwNumRegions)
{
g_DownloadManifest.dwNumRegions = 1; //声明*.bin有一条记录
g_DownloadManifest.Region[0].dwRegionStart = dwImageStart; //声明这条记录的起始地址
g_DownloadManifest.Region[0].dwRegionLength = dwImageLength;//声明这条记录的映像长度
// Provide the download manifest to the OEM.
if (g_pOEMMultiBINNotify)
{
g_pOEMMultiBINNotify((PDownloadManifest)&g_DownloadManifest);
}
}
// Locate the current download manifest entry (current download file).
pCurDownloadFile = &g_DownloadManifest.Region[g_DownloadManifest.dwNumRegions - nNumDownloadFiles];//当前下载文件指向*.bin开始
// give the OEM a chance to verify memory.内存校验
if (g_pOEMVerifyMemory && !g_pOEMVerifyMemory (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
EdbgOutputDebugString ("!OEMVERIFYMEMORY: Invalid image/r/n");//lqm:很多情况下都会执行到这里!映像不能获得?
HALT (BLERR_OEMVERIFY);
return (FALSE);
}
// check for flash image. Start erasing if it is.
if ( (fIsFlash = OEMIsFlashAddr(pCurDownloadFile->dwRegionStart))//lqm:校验起始地址是否在Flash相应地址区域,如果是则擦除相应下载区域
&& !OEMStartEraseFlash (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
EdbgOutputDebugString ("Invalid Flash Address/Length/r/n");
HALT (BLERR_FLASHADDR);
return (FALSE);
}
// if we're downloading a binary file, we've already downloaded part of the image when searching
// for a file header. copy what we've read so far to the destination buffer, then finish downloading.
if (!g_bBINDownload)
{
lpDest = OEMMapMemAddr (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionStart);
memcpy(lpDest, hdr, BL_HDRSIG_SIZE);
// complete the file download...
// read data block
if (!OEMReadData ((pCurDownloadFile->dwRegionLength - BL_HDRSIG_SIZE), (lpDest + BL_HDRSIG_SIZE)))
{
EdbgOutputDebugString ("ERROR: failed when reading raw binary file./r/n");
HALT (BLERR_CORRUPTED_DATA);
return (FALSE);
}
}
// we're downloading a .bin file - download each .bin record in turn...
else//开始下载*.bin文件到DRAM中。
{
while (OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecAddr) && //读取*.bin的第n条记录的地址.
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecLen) && //读取*.bin的第n条记录的长度.
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk)) //读取*.bin的第n条记录的校验和.
{
// last record of .bin file uses sentinel values for address and checksum.
// 最后一条记录表示结束.其地址和校验和均为0.
if (!dwRecAddr && !dwRecChk)
{
break;//读到最后一条记录时跳出循环
}
// map the record address (FLASH data is cached, for example)
// 将存入的记录地址映射到指针地址lpDest
lpDest = OEMMapMemAddr (pCurDownloadFile->dwRegionStart, dwRecAddr);
// read data block
if (!OEMReadData (dwRecLen, lpDest))//读取*.bin的第n条记录的内容到lpDest.这里先把*.bin的数据读到DRAM中。