Chinaunix首页 | 论坛 | 博客
  • 博客访问: 90107
  • 博文数量: 34
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 275
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-13 23:05
文章分类

全部博文(34)

文章存档

2011年(1)

2010年(7)

2009年(26)

我的朋友

分类: 嵌入式

2009-12-18 10:10:21

   开始正式学习wince的程序开发和源码解, 硬件广州朗成的PW2440开发板,CPU是arm9的s3c2440,具体去网站看。软件是VS2005和一系列的补丁,wince500, evc4.0等,先用pb导出SDK,再安装就可以使用evc了。
    书籍《Windows CE 工程实践完全解析》细节原理写的不错。

========1. bootloader实现========
---- 1.1 blcommon实现
%WINCEROOT%\PUBLIC\COMMON\OAK\INC\blcommon.h

    Bootloader common header file. This file contains all the type and
    function definitions used by boot loader.
   
CheckSignature()
BootloaderMain()
RegionInfo
MultiBINInfo

还有一些列的 OEM***() 函数, 通过函数指针在开发板的BSP中实现。如SMDK2440a的eboot\ether.c里面
// Function pointers to the support library functions of the currently installed debug ethernet controller.
//
PFN_EDBG_INIT             pfnEDbgInit;
PFN_EDBG_ENABLE_INTS      pfnEDbgEnableInts;
PFN_EDBG_DISABLE_INTS     pfnEDbgDisableInts;
PFN_EDBG_GET_PENDING_INTS pfnEDbgGetPendingInts;
PFN_EDBG_GET_FRAME        pfnEDbgGetFrame;
PFN_EDBG_SEND_FRAME       pfnEDbgSendFrame;
PFN_EDBG_READ_EEPROM      pfnEDbgReadEEPROM;
PFN_EDBG_WRITE_EEPROM     pfnEDbgWriteEEPROM;
PFN_EDBG_SET_OPTIONS      pfnEDbgSetOptions;

同文件夹还有格式化字符串等函数文件format.c和输出映像文件的特征检测代码signature.c(bib)
--------------------------
%WINCEROOT%\PUBLIC\Common\Oak\Drivers\EThdbg\blcommon.c

    ROMHDR * volatile const pTOC = (ROMHDR *)-1;     // Gets replaced by RomLoader with real address

/*
 *  关机(挂起)函数 
 */

static void HALT (DWORD dwReason)
{
    if (g_pOEMReportError)
    {
        g_pOEMReportError (dwReason, 0);
    }
    SPIN_FOREVER; // #define SPIN_FOREVER while (1) //死循环挂起

}



/*
 * BootloaderMain
 */



void BootloaderMain (void)
{
    DWORD dwAction;
    DWORD dwpToc = 0;
    DWORD dwImageStart = 0, dwImageLength = 0, dwLaunchAddr = 0;
    BOOL bDownloaded = FALSE;

    // relocate globals to RAM

    if (!KernelRelocate (pTOC))
    {
        // spin forever

        HALT (BLERR_KERNELRELOCATE);
    }

    // (1) Init debug support. We can use OEMWriteDebugString afterward.

    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

    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

    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.

        //

        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);
    }
}


/*
 * KernelRelocal
 */


//

// KernelRelocate: move global variables to RAM

//

static BOOL KernelRelocate (ROMHDR *const pTOC)
{
    ULONG loop;
    COPYentry *cptr;
    if (pTOC == (ROMHDR *const) -1)
    {
        return (FALSE); // spin forever!

    }
    // This is where the data sections become valid... don't read globals until after this

    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);
        if (cptr->ulCopyLen != cptr->ulDestLen)
            memset((LPVOID)(cptr->ulDest+cptr->ulCopyLen),0,cptr->ulDestLen-cptr->ulCopyLen);
    }
    return (TRUE);
}


/*
 * DownloadImage()
 */

#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"

        //

        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))
        {
            // 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);
            }

            // 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.

        //

        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))
        {
            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.

        //

        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.

            //

            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.

        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);
}


/*
 * VerifyChecksum ()
 */

static BOOL VerifyChecksum (DWORD cbRecord, LPBYTE pbRecord, DWORD dwChksum)
{
    // Check the CRC

    DWORD dwCRC = 0;
    DWORD i;
    for (i = 0; i < cbRecord; i++)
        dwCRC += *pbRecord ++; //字节累加校验和

    if (dwCRC != dwChksum)
        EdbgOutputDebugString ("ERROR: Checksum failure (expected=0x%x computed=0x%x)\r\n", dwChksum, dwCRC);

    return (dwCRC == dwChksum);
}


/*
 * IsKernelRegion()
 */


static BOOL IsKernelRegion(DWORD dwRegionStart, DWORD dwRegionLength)
{
    DWORD dwCacheAddress = 0;
    ROMHDR *pROMHeader;
    DWORD dwNumModules = 0;
    TOCentry *plTOC;

    if (dwRegionStart == 0 || dwRegionLength == 0)
        return(FALSE);

    if (*(LPDWORD) OEMMapMemAddr (dwRegionStart, dwRegionStart + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE)
        return (FALSE);

    // A pointer to the ROMHDR structure lives just past the ROM_SIGNATURE (which is a longword value). Note that

    // this pointer is remapped since it might be a flash address (image destined for flash), but is actually cached

    // in RAM.

    //

    dwCacheAddress = *(LPDWORD) OEMMapMemAddr (dwRegionStart, dwRegionStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG));
    pROMHeader = (ROMHDR *) OEMMapMemAddr (dwRegionStart, dwCacheAddress + g_dwROMOffset);

    // Make sure sure are some modules in the table of contents.

    //

    if ((dwNumModules = pROMHeader->nummods) == 0)
        return (FALSE);

    // Locate the table of contents and search for the kernel executable and the TOC immediately follows the ROMHDR.

    //

    plTOC = (TOCentry *)(pROMHeader + 1);

    while(dwNumModules--) {
        LPBYTE pFileName = OEMMapMemAddr(dwRegionStart, (DWORD)plTOC->lpszFileName + g_dwROMOffset);
        if (!strcmp(pFileName, "nk.exe")) {
            return TRUE;
        }
        ++plTOC;
    }
    return FALSE;
}


阅读(1688) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~