startup.s對底層進行初始化後,調用main()此函數一般位於main.c下面
main函數調用BLCOMMON.c下的BootloaderMain()函數,bootloader的主控權喪失。
學習何老師書的內容摘抄如下:
//目錄是%/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/ETHDBG/BLCOMMON下的BLCOMMON.c文件中的內容
void BootloaderMain (void)
{
DWORD dwAction;
DWORD dwpToc = 0;
DWORD dwImageStart = 0, dwImageLength = 0, dwLaunchAddr = 0;
BOOL bDownloaded = FALSE;
// relocate globals to RAM// 把全局變量定位到ram
if (!KernelRelocate (pTOC))
{
// spin forever //出錯處理
HALT (BLERR_KERNELRELOCATE);
}
// (1) Init debug support. We can use OEMWriteDebugString afterward.
//初始化調試端口,我們就可以使用OEMWriteDebugString 函數
if (!OEMDebugInit ())
{
// spin forever
HALT (BLERR_DBGINIT);
}
// output banner
EdbgOutputDebugString (NKSignon, CURRENT_VERSION_MAJOR, CURRENT_VERSION_MINOR);
// (3) initialize platform (clock, drivers, transports, etc)
//初始化平臺(時鐘,驅動,和傳輸)
if (!OEMPlatformInit ())
{
// spin forever
HALT (BLERR_PLATINIT);
}
// system ready, preparing for download
EdbgOutputDebugString ("System ready!/r/nPreparing for download.../r/n");
// (4) call OEM specific pre-download function
//調用OEM編寫的OEMPreDownload函數決定是否下載
switch (dwAction = OEMPreDownload ())
{
case BL_DOWNLOAD:
// (5) download image
//下載鏡像
if (!DownloadImage (&dwImageStart, &dwImageLength, &dwLaunchAddr))
{
// error already reported in DownloadImage
SPIN_FOREVER;
}
bDownloaded = TRUE;
// Check for pTOC signature ("CECE") here, after image in place
//檢測下載鏡像的簽名
if (*(LPDWORD) OEMMapMemAddr (dwImageStart, dwImageStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)
{
dwpToc = *(LPDWORD) OEMMapMemAddr (dwImageStart, dwImageStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG));
// need to map the content again since the pointer is going to be in a fixup address
//再一次映射內容
dwpToc = (DWORD) OEMMapMemAddr (dwImageStart, dwpToc + g_dwROMOffset);
EdbgOutputDebugString ("ROMHDR at Address %Xh/r/n", dwImageStart + ROM_SIGNATURE_OFFSET + sizeof (DWORD)); //
right after signature
}
// fall through
//沒有break,下載後直接繼續執行
case BL_JUMP:
// Before jumping to the image, optionally check the image signature.
// NOTE: if we haven't downloaded the image by now, we assume that it'll be loaded from local storage in OEMLaunch
(or it
// already resides in RAM from an earlier download), and in this case, the image start address might be 0. This
means
// that the image signature routine will need to find the image in storage or in RAM to validate it. Since the OEM"s
// OEMLaunch function will need to do this anyways, we trust that it's within their abilities to do it here.
//
//在啓動操作系統之前,再次檢查簽名,如果沒有下載,那麼OEMLauch函數應該有能力
//啓動存在本地存儲中的鏡像
if (g_bBINDownload && g_pOEMCheckSignature)
{
if (!g_pOEMCheckSignature(dwImageStart, g_dwROMOffset, dwLaunchAddr, bDownloaded))
HALT(BLERR_CAT_SIGNATURE);
}
// (5) final call to launch the image. never returned
//最終啓動操作系統鏡像,此函數不會返回
OEMLaunch (dwImageStart, dwImageLength, dwLaunchAddr, (const ROMHDR *)dwpToc);
// should never return
//不應該執行到這裏
// fall through
default:
// ERROR! spin forever
//出錯
HALT (BLERR_INVALIDCMD);
}
}
/*
重定位函數KernelRelocate ()
重定位的目的是:確保全局變量可被寫
(主要防止在只讀介質上運行BootLoader的時候出錯,重新將全局變量定位到RAM中就實現全局變量的可寫)
pTOC定義在BLCommon.c文件中: ROMHDR * volatile const pTOC=(ROMHDR *)-1;
ROMHDR指針描述整個ROM的幾乎所有信息,但代碼本身不帶有ROM信息
那麼pTOC什麼時候被初始化的呢?
全局變量pTOC使用RomImage.exe把EBOOT打包爲ROM文件的時候初始化的
*/
static BOOL KernelRelocate (ROMHDR *const pTOC)
{
ULONG loop;
COPYentry *cptr;
//如果pTOC爲-1,則重定位失敗
if (pTOC == (ROMHDR *const) -1)
{
return (FALSE); // spin forever!
}
// This is where the data sections become valid... don't read globals until after this
//根據pTOC結構體的信息,獲得要複製的源地址、目標地址和長度
for (loop = 0; loop < pTOC->ulCopyEntries; loop++)
{
cptr = (COPYentry *)(pTOC->ulCopyOffset + loop*sizeof(COPYentry));
if (cptr->ulCopyLen)
memcpy((LPVOID)cptr->ulDest,(LPVOID)cptr->ulSource,cptr->ulCopyLen);
//把多餘的地址置0
if (cptr->ulCopyLen != cptr->ulDestLen)
memset((LPVOID)(cptr->ulDest+cptr->ulCopyLen),0,cptr->ulDestLen-cptr->ulCopyLen);
}
return (TRUE);
}
/*
OEMDebugInit()初始化調試端口函數一般在BSP中的“SRC/BOOTLOADER/EBOOT”Main.c文件裏面。
OEMDebugInit()一般調用OEMInitDebugSerial()函數來初始化串口,對UART1端口進行初始化,
這樣我們就可以通過超級終端看打印信息咯~
*/
/*OEMPlatformInit()函數
@func BOOL | OEMPlatformInit | Initialize the Samsung SMD2410 platform hardware.
@rdesc TRUE = Success, FALSE = Failure.
@comm
@xref
初始化目標板上的設備函數OEMPlatformInit()函數,主要使得EBoot成功使用一些設備
如: 1、實時鐘(用於網絡下載及用戶輸入判斷);
2、顯示屏(用於操作系統啓動時,在屏幕上顯示的logo等信息)
3、Flash(鏡像下載後須燒錄到Flash中或者其他方式要使用Flash。此外,FMD驅動程序也可以在此初始化)
4、網卡(EBoot通過網卡下載鏡像。在這裏可以初始化網卡,包括MAC地址,I/O方式等)
5、BSP的共享參數(OAL與EBoot會共享一些參數,即EBoot會將一些參數傳給OAL使用,在此可以給參數初始化)
6、此外,要在EBoot中輸出菜單的超級終端中與界面交互,也可以在此使用
*/
BOOL OEMPlatformInit(void)
{
UINT8 BootDelay;
UINT8 KeySelect;
UINT32 dwStartTime, dwPrevTime, dwCurrTime;
PCI_REG_INFO NANDInfo;
BOOLEAN bResult = FALSE;
OALMSG(OAL_FUNC, (TEXT("+OEMPlatformInit./r/n")));
EdbgOutputDebugString("Microsoft Windows CE Bootloader for the Samsung SMDK2410 Version %d.%d Built %s/r/n/r/n",
EBOOT_VERSION_MAJOR, EBOOT_VERSION_MINOR, __DATE__);
// Initialize the display.
//
//初始化顯示設備
InitDisplay();
//可以在InitDisplay()完成之後,用memcpy把定義在bitmap.c中的數組複製到幀緩衝內,從而實現開機啓動畫面
// Initialize the RealTimeClock
//初始化實時時鐘,因爲後面許多判斷超時需要用到,所以這一步驟是必須的
InitRealTimeClock();
// Initialize the BSP args structure.
//初始化BSP的共享參數,在2410 EBoot中定義了一個叫pBSPArgs的區域指針(loader.h文件中)
//#define IMAGE_SHARE_ARGS_UA_START 0xAC020000
//#define pBSPArgs ((BSP_ARGS *)IMAGE_SHARE_ARGS_US_START)
//BSP_ARGS結構體有3個數據域:OAL_ARGS_HEADER描述版本信息和簽名;
deviceID設備的描述符
OAL_LITL_ARGS是KITL的一些信息,系統啓動時候可以從共享中讀取一些信息
//Bootloader把信息寫入這個內存區域,在OAL中就可以直接讀取
memset(pBSPArgs, 0, sizeof(BSP_ARGS));
pBSPArgs->header.signature = OAL_ARGS_SIGNATURE;
pBSPArgs->header.oalVersion = OAL_ARGS_VERSION;
pBSPArgs->header.bspVersion = BSP_ARGS_VERSION;
pBSPArgs->kitl.flags = OAL_KITL_FLAGS_ENABLED | OAL_KITL_FLAGS_VMINI;
pBSPArgs->kitl.devLoc.IfcType = Internal;
pBSPArgs->kitl.devLoc.BusNumber = 0;
pBSPArgs->kitl.devLoc.LogicalLoc = BSP_BASE_REG_PA_CS8900A_IOBASE;
// Initialize the AMD AM29LV800 flash code.
//初始化AM29LV800芯片和Flash驅動
//AM29LV800芯片用於保存啓動信息
//Flash驅動初始化,直接調用FMD_Init()函數
if (!AM29LV800_Init((UINT32)AMD_FLASH_START))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMPlatformInit: Flash initialization failed./r/n")));
goto CleanUp;
}
// Initialize the Smart Media flash driver (and partitioning code).
//
memset(&NANDInfo, 0, sizeof(PCI_REG_INFO));
NANDInfo.MemBase.Num = 1;
NANDInfo.MemBase.Reg[0] = (DWORD)OALPAtoVA(S3C2410X_BASE_REG_PA_NAND, FALSE);
if (!FMD_Init(NULL, &NANDInfo, NULL))
{
OALMSG(OAL_WARN, (TEXT("WARNING: OEMPlatformInit: Failed to initialize Smart Media./r/n")));
g_bSmartMediaExist = FALSE;
}
else
{
g_bSmartMediaExist = TRUE;
}
// Retrieve eboot settings from AMD flash.
// EBoot從AM29LV800芯片中讀取啓動信息
if (!ReadBootConfig(&g_BootConfig))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMPlatformInit: Failed to retrieve bootloader settings from flash./r/n")));
goto CleanUp;
}
// Display boot message - user can halt the autoboot by pressing any key on the serial terminal emulator.
//檢測用戶在規定的時間內、在開發終端上,有無按鍵按下;有則,調用MainMenu函數打印啓動菜單
BootDelay = g_BootConfig.BootDelay;
EdbgOutputDebugString ( "Press [ENTER] to download now or [SPACE] to cancel./r/n");
EdbgOutputDebugString ( "/r/nInitiating image download in %d seconds. ", BootDelay--);
//得到當前時間
dwStartTime = OEMEthGetSecs();
dwPrevTime = dwStartTime;
dwCurrTime = dwStartTime;
KeySelect = 0;
// Allow the user to break into the bootloader menu.
//在BootDelay指定的時間內等待用戶按鍵
while((dwCurrTime - dwStartTime) < g_BootConfig.BootDelay)
{
KeySelect = OEMReadDebugByte();//讀取用戶按鍵
if ((KeySelect == 0x20) || (KeySelect == 0x0d))
break;
dwCurrTime = OEMEthGetSecs();//獲得當前時間
//向用戶回顯剩餘的等待時間
if (dwCurrTime > dwPrevTime)
{
int i, j;
// 1 Second has elapsed - update the countdown timer.
dwPrevTime = dwCurrTime;
if (BootDelay < 9)
i = 11;
else if (BootDelay < 99)
i = 12;
else if (BootDelay < 999)
i = 13;
for(j = 0; j < i; j++)
OEMWriteDebugByte((BYTE)0x08); // print back space
EdbgOutputDebugString ( "%d seconds. ", BootDelay--);
}
}
EdbgOutputDebugString ( "/r/n");
// Boot or enter bootloader menu.
//判斷用戶按鍵情況
switch(KeySelect)
{
case 0x20: // Boot menu.打印BootMenu
MainMenu(&g_BootConfig);
break;
case 0x00: // Fall through if no keys were pressed -or-直接啓動
case 0x0d: // the user cancelled the countdown.
default:
EdbgOutputDebugString ( "/r/nStarting auto-download ... /r/n");
break;
}
// Configure Ethernet controller.
//調用InitEthDevice()初始化以太網
if (!InitEthDevice(&g_BootConfig))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMPlatformInit: Failed to initialize Ethernet controller./r/n")));
goto CleanUp;
}
bResult = TRUE;
CleanUp:
OALMSG(OAL_FUNC, (TEXT("_OEMPlatformInit./r/n")));
return(bResult);
}
/*位於main.c文件中
@func BOOL | MainMenu | Manages the Samsung bootloader main menu.
@rdesc TRUE == Success and FALSE == Failure.
@comm
@xref
*/
//實現用於與用戶交互的菜單
static BOOL MainMenu(PBOOT_CFG pBootCfg)
{
BYTE KeySelect = 0;
BOOL bConfigChanged = FALSE;
while(TRUE)
{
KeySelect = 0;
//打印菜單
EdbgOutputDebugString ( "/r/nEthernet Boot Loader Configuration:/r/n/r/n");
EdbgOutputDebugString ( "0) IP address: %s/r/n",inet_ntoa(pBootCfg->IPAddr));
EdbgOutputDebugString ( "1) Subnet mask: %s/r/n", inet_ntoa(pBootCfg->SubnetMask));
EdbgOutputDebugString ( "2) DHCP: %s/r/n", (pBootCfg->ConfigFlags & CONFIG_FLAGS_DHCP)?"Enabled":"Disabled");
EdbgOutputDebugString ( "3) Boot delay: %d seconds/r/n", pBootCfg->BootDelay);
EdbgOutputDebugString ( "4) Reset to factory default configuration/r/n");
EdbgOutputDebugString ( "5) Program disk image into SmartMedia card: %s/r/n", (pBootCfg->ConfigFlags &
CONFIG_FLAGS_SAVETOFLASH)?"Enabled":"Disabled");
EdbgOutputDebugString ( "6) Program CS8900 MAC address/r/n");
EdbgOutputDebugString ( "7) Low-level format the Smart Media card/r/n");
EdbgOutputDebugString ( "D) Download image now/r/n");
EdbgOutputDebugString ( "/r/nEnter your selection: ");
while (! ( ( (KeySelect >= '0') && (KeySelect <= '7') ) ||
( (KeySelect == 'D') || (KeySelect == 'd') ) ))
{
KeySelect = OEMReadDebugByte();//讀取用戶按鍵
}
EdbgOutputDebugString ( "%c/r/n", KeySelect);
switch(KeySelect) //根據用戶按鍵進行不同操作
{
case '0': // Change IP address.
SetIP(pBootCfg);
bConfigChanged = TRUE;
break;
case '1': // Change subnet mask.
SetMask(pBootCfg);
bConfigChanged = TRUE;
break;
case '2': // Toggle static/DHCP mode.
pBootCfg->ConfigFlags = (pBootCfg->ConfigFlags ^ CONFIG_FLAGS_DHCP);
bConfigChanged = TRUE;
break;
case '3': // Change autoboot delay.
SetDelay(pBootCfg);
bConfigChanged = TRUE;
break;
case '4': // Reset the bootloader configuration to defaults.
ResetBootConfig(pBootCfg);
bConfigChanged = TRUE;
break;
case '5': // Toggle image storage to Smart Media.
pBootCfg->ConfigFlags = (pBootCfg->ConfigFlags ^ CONFIG_FLAGS_SAVETOFLASH);
bConfigChanged = TRUE;
break;
case '6': // Configure Crystal CS8900 MAC address.
SetCS8900MACAddress(pBootCfg);
bConfigChanged = TRUE;
break;
case '7': // Format the Smart Media card.
if (g_bSmartMediaExist && !FormatSmartMedia())
{
RETAILMSG(1, (TEXT("ERROR: Failed to perform low-level format of SmartMedia card./r/n")));
}
break;
case 'D': // Download? Yes.
case 'd':
goto MENU_DONE;
break;
default:
break;
}
}
MENU_DONE:
// If eboot settings were changed by user, save them to flash.
//把用戶的修改重新寫回AM29LV800 Flash中
if (bConfigChanged && !WriteBootConfig(pBootCfg))
{
OALMSG(OAL_WARN, (TEXT("WARNING: MainMenu: Failed to store updated bootloader configuration to flash./r/n")));
}
return(TRUE);
}
//位於Ethernet.c文件中
BOOL InitEthDevice(PBOOT_CFG pBootCfg)
{
PBYTE pBaseIOAddress = NULL;
UINT32 MemoryBase = 0;
BOOL bResult = FALSE;
OALMSG(OAL_FUNC, (TEXT("+InitEthDevice./r/n")));
// Use the MAC address programmed into flash by the user.
//
memcpy(pBSPArgs->kitl.mac, pBootCfg->CS8900MAC, 6);
// Use the CS8900A Ethernet controller for download.
//第一步,註冊Eboot用到的以太網回調函數
pfnEDbgInit = CS8900DBG_Init;
pfnEDbgGetFrame = CS8900DBG_GetFrame;
pfnEDbgSendFrame = CS8900DBG_SendFrame;
//取得網卡的IO的基地址與內存基地址
pBaseIOAddress = (PBYTE)OALPAtoVA(pBSPArgs->kitl.devLoc.LogicalLoc, FALSE);
MemoryBase = (UINT32)OALPAtoVA(BSP_BASE_REG_PA_CS8900A_MEMBASE, FALSE);
// Initialize the Ethernet controller.
//第二步,調用Init()函數
if (!pfnEDbgInit((PBYTE)pBaseIOAddress, MemoryBase, pBSPArgs->kitl.mac))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Failed to initialize Ethernet
controller./r/n")));
goto CleanUp;
}
// Make sure MAC address has been programmed.
//
if (!pBSPArgs->kitl.mac[0] && !pBSPArgs->kitl.mac[1] && !pBSPArgs->kitl.mac[2])
{
OALMSG(OAL_ERROR, (TEXT("ERROR: InitEthDevice: Invalid MAC address./r/n")));
goto CleanUp;
}
bResult = TRUE;
CleanUp:
OALMSG(OAL_FUNC, (TEXT("-InitEthDevice./r/n")));
return(bResult);
}
/*OEMPreDownload(void) Main.c文件
@func DWORD | OEMPreDownload | Complete pre-download tasks - get IP address, initialize TFTP, etc.
@rdesc BL_DOWNLOAD = Platform Builder is asking us to download an image, BL_JUMP = Platform Builder is requesting we
jump to an existing image, BL_ERROR = Failure.
@comm
@xref
*/
DWORD OEMPreDownload(void)
{
BOOL bGotJump = FALSE;
DWORD dwDHCPLeaseTime = 0;
PDWORD pdwDHCPLeaseTime = &dwDHCPLeaseTime;
DWORD dwBootFlags = 0;
// Create device name based on Ethernet address (this is how Platform Builder identifies this device).
//調用OALKitlCreateNam()爲設備創建一個獨一無二的名字
OALKitlCreateName(BSP_DEVICE_PREFIX, pBSPArgs->kitl.mac, pBSPArgs->deviceId);
OALMSG(TRUE, (L"INFO: *** Device Name '%hs' ***/r/n", pBSPArgs->deviceId));
// If the user wants to use a static IP address, don't request an address
// from a DHCP server. This is done by passing in a NULL for the DHCP
// lease time variable. If user specified a static IP address, use it (don't use DHCP).
//
if (!(g_BootConfig.ConfigFlags & CONFIG_FLAGS_DHCP))
{
// Static IP address.
pBSPArgs->kitl.ipAddress = g_BootConfig.IPAddr;
pBSPArgs->kitl.ipMask = g_BootConfig.SubnetMask;
pBSPArgs->kitl.flags &= ~OAL_KITL_FLAGS_DHCP;
pdwDHCPLeaseTime = NULL;
OALMSG(TRUE, (TEXT("INFO: Using static IP address %s./r/n"), inet_ntoa(pBSPArgs->kitl.ipAddress)));
OALMSG(TRUE, (TEXT("INFO: Using subnet mask %s./r/n"), inet_ntoa(pBSPArgs->kitl.ipMask)));
}
else
{
pBSPArgs->kitl.ipAddress = 0;
pBSPArgs->kitl.ipMask = 0;
}
// Initialize the the TFTP transport.
//調用EbootInitEtherTransport()函數,完成網絡大多數的初始化任務
/*
1)EbootInitEtherTransport()根據參數判斷是否採用DHCP動態獲取IP地址;
YES,則通過EbootGetDHCPAddr()從DHCP服務器獲取新IP地址;
NO,則使用用戶配置的靜態IP;
2)通過EbootCheckIP()檢測當前IP是否可用(通過發送ARP包,判斷是否有衝突。沒有,則表示IP可用;
3)通過EbootInitTftpSimple()函數在目標機端初始化Tftp服務器(扮演Tftp協議中的服務器角色的是開發板,客戶端角色的是pc機);
4)建立服務器與客戶端之間的握手;
開發板Eboot(a) PC機 PB_IDEb)
(a)向整個網段發送BOOTME消息(告訴PC機已經做好接受鏡像的準備好了)
(b)接收到BOOTME消息後,PC端向開發板Eboot發送ACK信號,並根據用戶的配置進行相應操作(告訴Eboot是下載或者進行Tftp連接)
*/
g_DeviceAddr.dwIP = pBSPArgs->kitl.ipAddress;
memcpy(g_DeviceAddr.wMAC, pBSPArgs->kitl.mac, (3 * sizeof(UINT16)));
g_DeviceAddr.wPort = 0;
if (!EbootInitEtherTransport(&g_DeviceAddr,
&pBSPArgs->kitl.ipMask,
&bGotJump,
pdwDHCPLeaseTime,
EBOOT_VERSION_MAJOR,
EBOOT_VERSION_MINOR,
BSP_DEVICE_PREFIX,
pBSPArgs->deviceId,
EDBG_CPU_ARM720,
dwBootFlags))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMPreDownload: Failed to initialize Ethernet connection./r/n")));
return(BL_ERROR);
}
// If the user wanted a DHCP address, we presumably have it now - save it for the OS to use.
//
if (g_BootConfig.ConfigFlags & CONFIG_FLAGS_DHCP)
{
// DHCP address.
pBSPArgs->kitl.ipAddress = g_DeviceAddr.dwIP;
pBSPArgs->kitl.flags |= OAL_KITL_FLAGS_DHCP;
}
return(bGotJump ? BL_JUMP : BL_DOWNLOAD);
}
//downloadimage函數blcommon.c
#define BL_HDRSIG_SIZE 7
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;
*pdwImageStart = *pdwImageLength = *pdwLaunchAddr = 0;
do
{
// read the 7 byte "magic number"
//讀取7字節的魔術碼
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.
//N000FF包,由PB發出(當我們下載多文件或者下載.NB0文件)
//N000FF表示要下載多個BIN
if (!memcmp (hdr, "N000FF/x0A", BL_HDRSIG_SIZE))
{
// 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).
//讀取BIN種類
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);
}
// Provide the download manifest to the OEM. This gives the OEM the
// opportunity to provide start addresses for the .nb0 files (which
// don't contain placement information like .bin files do).
//
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.
//不支持X000FF的multi-bin包
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.
//標準的BIN鏡像,檢查正常的bin文件名
else if (!memcmp (hdr, "B000FF/x0A", BL_HDRSIG_SIZE))
{
g_bBINDownload = TRUE;
if (!OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageStart)
|| !OEMReadData (sizeof (DWORD), (LPBYTE) &dwImageLength))
{
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.
//如果頭文件頭無法識別,就假設該下載的文件爲生疏的.NB0文件
else
{
g_bBINDownload = FALSE;
}
// If Platform Builder didn't provide a download manifest (i.e., we're
// only downloading a single .bin file), manufacture a manifest so we
// can notify the OEM.
//
if (!g_DownloadManifest.dwNumRegions)
{
g_DownloadManifest.dwNumRegions = 1;
g_DownloadManifest.Region[0].dwRegionStart = dwImageStart;
g_DownloadManifest.Region[0].dwRegionLength = dwImageLength;
// Provide the download manifest to the OEM.
//提供下載清單給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];
// give the OEM a chance to verify memory
//校驗內存
if (g_pOEMVerifyMemory && !g_pOEMVerifyMemory (pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
EdbgOutputDebugString ("!OEMVERIFYMEMORY: Invalid image/r/n");
HALT (BLERR_OEMVERIFY);
return (FALSE);
}
// check for flash image. Start erasing if it is.
//檢查是否爲flash鏡像,如果是則開始擦除
if ((fIsFlash = OEMIsFlashAddr (pCurDownloadFile->dwRegionStart))
&& !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
{
while (OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecAddr) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecLen) &&
OEMReadData (sizeof (DWORD), (LPBYTE) &dwRecChk))
{
// last record of .bin file uses sentinel values for address and checksum.
if (!dwRecAddr && !dwRecChk)
{
break;
}
// map the record address (FLASH data is cached, for example)
lpDest = OEMMapMemAddr (pCurDownloadFile->dwRegionStart, dwRecAddr);
// read data block
if (!OEMReadData (dwRecLen, lpDest))
{
EdbgOutputDebugString ("****** Data record %d corrupted, ABORT!!! ******/r/n", nPkgNum);
HALT (BLERR_CORRUPTED_DATA);
return (FALSE);
}
if (!VerifyChecksum (dwRecLen, lpDest, dwRecChk))
{
EdbgOutputDebugString ("****** Checksum failure on record %d, ABORT!!! ******/r/n", nPkgNum);
HALT (BLERR_CHECKSUM);
return (FALSE);
}
// Look for ROMHDR to compute ROM offset. NOTE: romimage guarantees that the record containing
// the TOC signature and pointer will always come before the record that contains the ROMHDR contents.
//
if (dwRecLen == sizeof(ROMHDR) && (*(LPDWORD) OEMMapMemAddr(pCurDownloadFile->dwRegionStart,
pCurDownloadFile->dwRegionStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE))
{
DWORD dwTempOffset = (dwRecAddr - *(LPDWORD)OEMMapMemAddr(pCurDownloadFile->dwRegionStart,
pCurDownloadFile->dwRegionStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG)));
ROMHDR *pROMHdr = (ROMHDR *)lpDest;
// Check to make sure this record really contains the ROMHDR.
//
if ((pROMHdr->physfirst == (pCurDownloadFile->dwRegionStart - dwTempOffset)) &&
(pROMHdr->physlast == (pCurDownloadFile->dwRegionStart - dwTempOffset + pCurDownloadFile-
>dwRegionLength)) &&
(DWORD)(HIWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast) &&
(DWORD)(LOWORD(pROMHdr->dllfirst << 16) <= pROMHdr->dlllast))
{
g_dwROMOffset = dwTempOffset;
EdbgOutputDebugString("rom_offset=0x%x./r/n", g_dwROMOffset);
}
}
// verify partial checksum
OEMShowProgress (nPkgNum ++);
if (fIsFlash)
{
OEMContinueEraseFlash ();
}
}
}
// The image start address and length are passed back to the OEM code (OEMLaunch)
// in the following circumstances:
// 1. The file is a raw .nb0 file.
// 2. The file is a .bin file with a TOC that contains the kernel executable.
// 3. The file is a .bin file without a TOC.
//
// If the image is a .bin file with a TOC that doesn't contain the kernel exectuable,
// then it's a multi-xip/mulit-bin image for a non-kernel region and we don't pass
// the start address and length back to the OEM code. OEMLaunch can then save the
// start address and length with the assurance that if the values are non-zero, they
// represent the values for the NK region.
//
if (g_bBINDownload)
{
// Does this .bin file contain a TOC?
if (*(UINT32 *)(pCurDownloadFile->dwRegionStart + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)
{
// Contain the kernel?
if (IsKernelRegion(pCurDownloadFile->dwRegionStart, pCurDownloadFile->dwRegionLength))
{
*pdwImageStart = pCurDownloadFile->dwRegionStart;
*pdwImageLength = pCurDownloadFile->dwRegionLength;
*pdwLaunchAddr = dwRecLen;
}
}
// No TOC - not made by romimage. However, if we're downloading more than one
// .bin file, it's probably chain.bin which doesn't have a TOC (and which isn't
// going to be downloaded on its own) and we should ignore it.
//
else if (g_DownloadManifest.dwNumRegions == 1)
{
*pdwImageStart = pCurDownloadFile->dwRegionStart;
*pdwImageLength = pCurDownloadFile->dwRegionLength;
*pdwLaunchAddr = dwRecLen;
}
}
else // Raw binary file.
{
*pdwImageStart = pCurDownloadFile->dwRegionStart;
*pdwLaunchAddr = pCurDownloadFile->dwRegionStart;
*pdwImageLength = pCurDownloadFile->dwRegionLength;
}
// write to flash if it's flash image
if (fIsFlash)
{
// finish the flash erase
if (!OEMFinishEraseFlash ())
{
HALT (BLERR_FLASH_ERASE);
return (FALSE);
}
// Before writing the image to flash, optionally check the image signature.
if (g_bBINDownload && g_pOEMCheckSignature)
{
if (!g_pOEMCheckSignature(pCurDownloadFile->dwRegionStart, g_dwROMOffset, *pdwLaunchAddr, TRUE))
HALT(BLERR_CAT_SIGNATURE);
}
}
}
while (--nNumDownloadFiles);
if (fIsFlash)
{
nNumDownloadFiles = (BYTE)g_DownloadManifest.dwNumRegions;
while (nNumDownloadFiles--)
{
if (!OEMWriteFlash (g_DownloadManifest.Region[nNumDownloadFiles].dwRegionStart, g_DownloadManifest.Region
[nNumDownloadFiles].dwRegionLength))
{
HALT (BLERR_FLASH_WRITE);
return (FALSE);
}
}
}
return (TRUE);
}
/*OEMLaunch()函數 main.c文件
@func void | OEMLaunch | Executes the stored/downloaded image.
@rdesc N/A.
@comm
@xref
*/
void OEMLaunch( DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR *pRomHdr )
{
DWORD dwPhysLaunchAddr;
EDBG_OS_CONFIG_DATA *pCfgData;
EDBG_ADDR EshellHostAddr;
EDBG_ADDR DeviceAddr;
//是否把鏡像寫入NANDFlash
// If the user requested that a disk image (stored in RAM now) be written to the SmartMedia card, so it now.
//
if (g_BootConfig.ConfigFlags & CONFIG_FLAGS_SAVETOFLASH)
{
// Since this platform only supports RAM images, the image cache address is the same as the image RAM address.
//
if (!WriteDiskImageToSmartMedia(dwImageStart, dwImageLength, &g_BootConfig))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store image to Smart Media./r/n")));
goto CleanUp;
}
// Store the bootloader settings to flash.
//
// TODO: minimize flash writes.
//
if (!WriteBootConfig(&g_BootConfig))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store bootloader settings to flash./r/n")));
goto CleanUp;
}
OALMSG(TRUE, (TEXT("INFO: Disk image stored to Smart Media. Please Reboot. Halting.../r/n")));
while(1)
{
// Wait...
}
}
// Wait for Platform Builder to connect after the download and send us IP and port settings for service
// connections - also sends us KITL flags. This information is used later by the OS (KITL).
//調用EbootWaitForHostConnect得到PB設置
if (g_bWaitForConnect)
{
memset(&EshellHostAddr, 0, sizeof(EDBG_ADDR));
DeviceAddr.dwIP = pBSPArgs->kitl.ipAddress;
memcpy(DeviceAddr.wMAC, pBSPArgs->kitl.mac, (3 * sizeof(UINT16)));
DeviceAddr.wPort = 0;
if (!(pCfgData = EbootWaitForHostConnect(&DeviceAddr, &EshellHostAddr)))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: EbootWaitForHostConnect failed./r/n")));
goto CleanUp;
}
// If the user selected "passive" KITL (i.e., don't connect to the target at boot time), set the
// flag in the args structure so the OS image can honor it when it boots.
//
if (pCfgData->KitlTransport & KTS_PASSIVE_MODE)
{
pBSPArgs->kitl.flags |= OAL_KITL_FLAGS_PASSIVE;
}
}
// If a launch address was provided, we must have downloaded the image, save the address in case we
// want to jump to this image next time. If no launch address was provided, retrieve the last one.
//
if (dwLaunchAddr)
{
g_BootConfig.LaunchAddress = dwLaunchAddr;
}
else
{
dwLaunchAddr = g_BootConfig.LaunchAddress;
}
// Save bootloader settings in flash.
//把配置信息寫好Flash
// TODO: minimize flash writes.
//
if (!WriteBootConfig(&g_BootConfig))
{
OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store bootloader settings in flash./r/n")));
goto CleanUp;
}
// Jump to downloaded image (use the physical address since we'll be turning the MMU off)...
//關閉MMU
dwPhysLaunchAddr = (DWORD)OALVAtoPA((void *)dwLaunchAddr);
OALMSG(TRUE, (TEXT("INFO: OEMLaunch: Jumping to Physical Address 0x%Xh (Virtual Address 0x%Xh).../r/n/r/n/r/n"),
dwPhysLaunchAddr, dwLaunchAddr));
// Jump...
//
//跳轉到物理地址
Launch(dwPhysLaunchAddr);
CleanUp:
OALMSG(TRUE, (TEXT("ERROR: OEMLaunch: Halting.../r/n")));
SpinForever();
}
//Launch()位於util.s文件中
LEAF_ENTRY Launch
ldr r2, = PhysicalStart
ldr r3, = (VIR_RAM_START - PHY_RAM_START)
sub r2, r2, r3
mov r1, #0x0070 ; Disable MMU 禁止MMU
mcr p15, 0, r1, c1, c0, 0
nop
mov pc, r2 ; Jump to PStart 跳轉 因爲跳轉地址是物理地址,所以在跳轉前必須關閉MMU
nop
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/ymzhou117/archive/2010/04/16/5492313.aspx