四极管 EBOOT调试(下载功能OEM函数)
OEMReadData--------------------该函数负责从下载端口读取操作系统镜像数据
OEMMapMemAddr--------------当BOOTLOADER下载的操作系统镜像自身记录的目的存储位置是FLASH存储器时,该函数负责将它以重定向的方式暂存到一块RAM内存缓冲区中,待镜像数据下载全部完成以后再一起写入Flash存储器中。
OEMVerifyMemory-------------该函数在下载操作系统镜像的过程中向用户显示下载的进度。
先来看OEMMapMemAddr。
功能:在SDRAM中创建一个内核镜像缓存。
为什么会有这个机制,该函数用于当下载得到的操作系统镜像自身所记录的目的地址是Flash存储器时,该OEM函数要负责将镜像的数据以重定位的方式暂存到一块RAM内存缓冲区中去。由于向FALSH写数据的速度大大落后于从网络读取数据的数据量,而且写Flash之前通常还要执行擦除的操作,这更会影响到Flash的速度。所以Bootloader在下载操作系统镜像的同时将它写入Flash的做法是不可取的。合理的做法就是在系统的RAM内存中专门开辟一块暂存下载镜像数据的缓冲区,如果镜像的目的地址是指向Flash存储的,则待完成的镜像下载完成后再一起写入Flash。当然如果镜像的目的地址存储在RAM内存中。则不需要暂存,直接写入对应的区段内存地址即可。OEMVerifyMemory函数就必须要兼顾这两种甚至跟多的可能情况。
源码:
/*
@func LPBYTE | OEMMapMemAddr | Remaps a specified address to a file cache location. The file cache is used as a temporary store for flash images before they're written to flash.
@rdesc Corresponding address within a file cache area.
@comm
@xref
*/
LPBYTE OEMMapMemAddr(DWORD dwImageStart, DWORD dwAddr)
{
if (g_ImageType & IMAGE_TYPE_STEPLDR)
{
dwAddr = (FILE_CACHE_START + (dwAddr - STEPLDR_RAM_IMAGE_BASE));
return (LPBYTE)dwAddr;
}
else
if (g_ImageType & IMAGE_TYPE_LOADER)
{
dwAddr = (FILE_CACHE_START + (dwAddr - EBOOT_RAM_IMAGE_BASE));
return (LPBYTE)dwAddr;
}
else
if (g_ImageType & IMAGE_TYPE_RAWBIN)
{
OALMSG(TRUE, (TEXT("OEMMapMemAddr 0x%x 0x%x\r\n"),dwAddr,(FILE_CACHE_START + dwAddr)));
dwAddr = FILE_CACHE_START + dwAddr;
return (LPBYTE)dwAddr;
}
else
if (g_ImageType & IMAGE_TYPE_RAMIMAGE)
{
// We use the lowest address of all the BIN files being downloaded as the datum for temporarily caching
// the image in RAM prior to storage in flash...
//
if (!g_dwMinImageStart)
{
g_dwMinImageStart = dwImageStart;
}
// If it's a flash address, translate it by "rebasing" the address into the file cache area.
//
if (OEMIsFlashAddr(dwAddr) && (dwImageStart <= dwAddr))
{
dwAddr = (FILE_CACHE_START + (dwAddr - g_dwMinImageStart));
return((LPBYTE)dwAddr);
}
}
return (LPBYTE)dwAddr;
}
其中,g_ImageType定义在OEMDebugInit()函数的OEMVerifyMemory函数中定义
OEMDebugInit()函数是初始化调试端口(通常为调试串口)
BOOL OEMDebugInit(void)
{
// Set up function callbacks used by blcommon.
//
g_pOEMVerifyMemory = OEMVerifyMemory; // Verify RAM.
g_pOEMMultiBINNotify = OEMMultiBINNotify;
// RETAILMSG(1,(TEXT("OEMDebugInit() rGPBDAT = %x\n"),rGPBDAT));
//Call serial initialization routine (shared with the OAL).
//
OEMInitDebugSerial();
return(TRUE);
}
其中调用到两个函数指针。
在OEMVerifyMemory函数具体实现如下。
//------------------------------------------------------------------------------
//
// Function Name: OEMVerifyMemory( DWORD dwStartAddr, DWORD dwLength )
// Description..: This function verifies the passed address range lies
// within a valid region of memory. Additionally this function
// sets the g_ImageType if the image is a boot loader.
// Inputs.......: DWORD Memory start address
// DWORD Memory length
// Outputs......: BOOL - true if verified, false otherwise
//
//------------------------------------------------------------------------------
BOOL OEMVerifyMemory( DWORD dwStartAddr, DWORD dwLength )
{
OALMSG(TRUE, (TEXT("\r\n yang qi text Download BIN file information:\r\n")));
OALMSG(OAL_FUNC, (TEXT("+OEMVerifyMemory.\r\n")));
//RETAILMSG(1,(TEXT("OEMVerifyMemory() rGPBDAT = %x\n"),rGPBDAT));
// Is the image being downloaded the stepldr?
if ((dwStartAddr >= STEPLDR_RAM_IMAGE_BASE) &&
((dwStartAddr + dwLength - 1) < (STEPLDR_RAM_IMAGE_BASE + STEPLDR_RAM_IMAGE_SIZE)))
{
OALMSG(TRUE, (TEXT("Stepldr image\r\n")));
//Disp_String(1,Filename1,0,ITEM3_LINE+70,pDispMem,ASCII);
//Disp_String();
g_ImageType = IMAGE_TYPE_STEPLDR; // Stepldr image.
return TRUE;
}
// Is the image being downloaded the bootloader?
else if ((dwStartAddr >= EBOOT_STORE_ADDRESS) &&
((dwStartAddr + dwLength - 1) < (EBOOT_STORE_ADDRESS + EBOOT_STORE_MAX_LENGTH)))
{
OALMSG(TRUE, (TEXT("Eboot image\r\n")));
//Disp_String();
//Disp_String(1,Filename2,0,ITEM3_LINE+70,pDispMem,ASCII);
g_ImageType = IMAGE_TYPE_LOADER; // Eboot image.
return TRUE;
}
// Is it a ram image?
else if ((dwStartAddr >= ROM_RAMIMAGE_START) &&
((dwStartAddr + dwLength - 1) < (ROM_RAMIMAGE_START + ROM_RAMIMAGE_SIZE)))
{
OALMSG(TRUE, (TEXT("RAM image\r\n")));
//Disp_String(1,Filename3,0,ITEM3_LINE+70,pDispMem,ASCII);
g_ImageType = IMAGE_TYPE_RAMIMAGE;
return TRUE;
}
else if (!dwStartAddr && !dwLength)
{
OALMSG(TRUE, (TEXT("Don't support raw image\r\n")));
//Disp_String();
g_ImageType = IMAGE_TYPE_RAWBIN;
return FALSE;
}
// HACKHACK: get around MXIP images with funky addresses
OALMSG(TRUE, (TEXT("BIN image type unknow(0x%x, 0x%x)\r\n"), dwStartAddr, dwLength));
OALMSG(OAL_FUNC, (TEXT("_OEMVerifyMemory.\r\n")));
return FALSE;
}
在微软提供的BOOTLOADER源代码中,有些函数在调用之前,会先判断指向该地址的指针是否为空,为空则对该函数的调用不起作用。Bootloader中的这些函数,是我们可以根据自己的要求来选择实现的,并不是必须的。换句话说。少了他们,bootloader也照样可以工作。
如DownloadImage函数中对OEMVerifyMemory函数的调用
// give the OEM a chance to verify memory
if (g_pOEMVerifyMemory && !g_pOEMVerifyMemory
(pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
KITLOutputDebugString ("!OEMVERIFYMEMORY: Invalid image\r\n");
HALT (BLERR_OEMVERIFY);
return (FALSE);
}
(1)具体分析OEMVerifyMemory函数的作用
该函数可以用来检测某一段虚拟地址内存地址区域是否映射到实际可用的物理存储中,包括RAM或者NORFLASH。g_pOEMVerifyMemory是指向OEMVerifyMemory函数的函数指针。在Blocommon.c文件中有定义。
PFN_OEMVERIFYMEMORY g_pOEMVerifyMemory;
PFN_OEMVERIFYMEMORY是函数指针类型的定义,在Blcommon.h文件中定义:
typedef BOOL (* PFN_OEMVERIFYMEMORY) (DWORD dwStartAddr, DWORD dwLength);
如果要使用OEMVerityMemory函数则要给g_pOEMVerifyMemory赋值即可。
这样子赋值:
g_pOEMVerifyMemory = OEMVerityMemory;
二、OEMCHeckSignature OEMMultiBINNotify OEMReporError 等函数。
OEMCHeckSignature--------检验BIN文件的数字签名。
OEMMultiBINNotify----------当BOOTLOADER要下载夺取端操作系统镜像时调用此函数向用户发出通知。
OEMReporError-------------向用户报告BOOTLOADER的执行错误情况。都是选择实现的。
转载请注明出处。作者:四极管。广西师范大学 电子工程学院大学生科技创新基地 邮箱: [email protected]。