This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Updating Bootloader/NK.bin from application?

Other Parts Discussed in Thread: DM3730, OMAP3530

Hi,

I have OMAP3530/DM3730 custom boards, using WINCE 6.0 R3 and BSP_ARM_A8_1_02.  I need to update the bootloader and NK.bin from the Application.  I am thinking about sending an IOCTL command and a pointer to a buffer containing bootloader/NK.bin to a Kernel driver.  I am looking for FMD driver which can receive the command and do the erasing and flashing but I only see the FMD driver for NOR under "COMMON\SRC\COMMON\BOOT\FMD\" but not one NAND.

Would you please give me some guidance on how to update Bootloader / NK.bin from the Application?

I appreciate your help.

Luan

  • Hello,

    Looking further, I found fmd.c under "COMMON\SRC\SOC\COMMON_TI_V1\COMMON_TI\BLOCK\NAND".  To achieve that I described above, I did the followings:

    1.  I copies two functions WriteFlashEBOOT() and WriteFlashNK() from "PLATFORM\MYPLATFORM\SRC\BOOTLOADER\EBOOT\NAND\FLASH.C" to fmd.c.

    2. Add lib paths to sources file

    TARGETLIBS= \
        $(_TILIBS)\$(TI_COMMON)_oal_flashstore.lib  \
        $(_EBOOTLIBS)\$(_CPUDEPPATH)\bootpart.lib  \

    3. Do a local compile of BLOCK\NAND\DEVICE.  There is no compile error.

    4. Build Current BSP and Subprojects.  I have link errors with xldrnand.exe as below:

    BUILD: [01:0000002681:PROGC ] Linking C:\WINCE600\platform\Adenio2\target\ARMV4I\retail\xldrnand.exe
    BUILD: [01:0000002826:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol OALFlashStoreClose referenced in function NAND_WriteFlashXEL
    BUILD: [01:0000002827:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2001: unresolved external symbol dpCurSettings
    BUILD: [01:0000002828:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol OALFlashStoreWrite referenced in function NAND_WriteFlashXEL
    BUILD: [01:0000002829:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol OALFlashStoreOpen referenced in function NAND_WriteFlashXEL
    BUILD: [01:0000002830:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol BP_WriteData referenced in function NAND_WriteFlashNK
    BUILD: [01:0000002831:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol BP_SetDataPointer referenced in function NAND_WriteFlashNK
    BUILD: [01:0000002832:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol BP_OpenPartition referenced in function NAND_WriteFlashNK
    BUILD: [01:0000002833:ERRORE] common_ti_fmd_nand_boot.lib(fmd.obj) : error LNK2019: unresolved external symbol BP_Init referenced in function NAND_WriteFlashNK
    BUILD: [01:0000002834:ERRORE] C:\WINCE600\platform\Adenio2\target\ARMV4I\retail\xldrnand.exe : fatal error LNK1120: 8 unresolved externals

    Can any one please give me some tip on how to get around the above link errors or how to change bootloader and NK from FMD?

    Thanks,

    Luan

  • Hi Luan,

    how about declaring those libraries under sourcelibs?

    Thank You & Regards,

    GSR

     

  • Hello GSR,

    Thank you for your response.  I did try to put them under SOURCELIBS but I kept getting link errors after adding more and more libs, so I am not sure if the way I tried to do by copying code from the bootloader is correct.  What do you think?  How would you approach this task?

    Now, I am thinking about using FMD_EraseBlock() and FMD_WriteSector() to program XLDR/EBOOT and NK.bin.  However, I do not know which block and which sector to erase/flash?  For XLDR/EBOOT, I guess the block and sector must be 0 to start, but for NK.bin I am not sure.

    I would appreciate your guidance very much.

    Thanks,

    Luan

  • Hi Luan,

    The following would be the procedure that I follow,

    Enable messages while updaing XLDR and EBOOT in bootloader code.

    So, you will understand from which sector bootloader is flashing.

    Modify FMD Driver to have customized IOCTL to implement erasing sectors from the application, the area it should erase is related to XLDR and EBOOT.

    After erasing the buffer you passed to driver should validate the binary and then program to relevant location.

    The first thing shall be understanding Boot-loader code how it is doing all these operations.

    Regards,

    GSR

  • Luan,

    This is how we update the bootloader and NK from application software.

    First we extend the FMD (fmd.c) with a custom IOCTL as suggested by GSR:

    // Ensure this does not collide with other definitions in fmd.h
    #define IOCTL_FMD_RAW_WRITE_BLOCK      IOCTL_DISK_USER(20)

    typedef struct _RawWriteBlockReq
    {
        DWORD dwBlock;             // Block to write to
        LPBYTE pBuffer;            // Buffer to write
        DWORD cbBuffer;            // Size of buffer in bytes
    } RawWriteBlockReq, *PRawWriteBlockReq;

    BOOL
    FMD_OEMIoControl(
        DWORD code,
        UCHAR *pInBuffer,
        DWORD inSize,
        UCHAR *pOutBuffer,
        DWORD outSize,
        DWORD *pOutSize
        )
    {
        BOOL rc = FALSE;

        switch(code)
        {
        case IOCTL_FMD_RAW_WRITE_BLOCK:

            if (!pInBuffer || inSize != sizeof(RawWriteBlockReq))
            {
                SetLastError(ERROR_INVALID_PARAMETER);
                break;
            }

            rc = RawWriteBlock((PRawWriteBlockReq)pInBuffer);

            if(pOutSize)
            {
                *pOutSize = 0;
            }

            break;

        default:
            break;
        }

        return rc;
    }

    static BOOL RawWriteBlock(
        PRawWriteBlockReq pReq
        )
    {
        FlashInfo fi;
        DWORD cbBufferExpected;
        DWORD dwBlockStatus;

        DWORD dwBlock = pReq->dwBlock;
        LPBYTE pBuffer = pReq->pBuffer;
        DWORD cbBuffer = pReq->cbBuffer;

        if (!FMD_GetInfo(&fi))
        {
            SetLastError(ERROR_GEN_FAILURE);
            return FALSE;
        }  

        if (dwBlock >= fi.dwNumBlocks || !pBuffer)
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }  

        // Buffer must include SectorInfo.
        cbBufferExpected = fi.wSectorsPerBlock * (fi.wDataBytesPerSector + sizeof(SectorInfo));
        if (cbBuffer != cbBufferExpected)
        {
            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }  

        dwBlockStatus = FMD_GetBlockStatus(dwBlock);
        if (dwBlockStatus & BLOCK_STATUS_BAD)
        {
            SetLastError(ERROR_BAD_UNIT);
            return FALSE;
        }

        if (!WriteBlock(fi, dwBlock, pBuffer))
        {
            // Write failed.

            // Mark block as bad.
            if (FMD_SetBlockStatus(dwBlock, BLOCK_STATUS_BAD))
            {
                SetLastError(ERROR_BAD_UNIT);
            }
            else
            {
                SetLastError(ERROR_GEN_FAILURE);
            }

            return FALSE;
        }
            
        return TRUE;
    }

    static BOOL WriteBlock(
        FlashInfo fi,
        DWORD dwBlock,
        LPBYTE pBuffer
        )
    {
        DWORD dwSector;
        DWORD dwStartSector = dwBlock * fi.wSectorsPerBlock;
        DWORD dwEndSector = dwStartSector + fi.wSectorsPerBlock;

        if (!FMD_EraseBlock(dwBlock))
        {
            return FALSE;
        }

        // Write out each sector one at a time. The buffer contains the sector data followed by the
        // SectorInfo for the particular sector.
        for (dwSector = dwStartSector; dwSector < dwEndSector; dwSector++)
        {
            PSectorInfo pSectorInfo = (PSectorInfo)(pBuffer + fi.wDataBytesPerSector);

            if (!FMD_WriteSector(dwSector, pBuffer, pSectorInfo, 1))
            {
                return FALSE;
            }

            pBuffer += (fi.wDataBytesPerSector + sizeof(SectorInfo));            
        }

        return TRUE;
    }

    Then we call the ioctl from the application as follows.

    // Assuming the flash driver loads as DSK0: ...
    DWORD access = GENERIC_READ | GENERIC_WRITE;
    DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE;
    HANDLE hOpen = CreateFile(L"DSK0:", access, share, NULL, OPEN_EXISTING, 0, NULL);

    RawWriteBlockReq req;
    ZeroMemory(&req, sizeof(req));
    req.dwBlock = 0 /* block number, zero-based */;
    req.pBuffer = NULL /* pointer to buffer, see below */;
    req.cbBuffer = 0 /* buffer length in bytes */;

    DeviceIoControl(hOpen, IOCTL_FMD_RAW_WRITE_BLOCK, &req, sizeof(req), NULL, 0, NULL, NULL);

    CloseHandle(hOpen);

    Data should be stored in the buffer as <sector 0 data> | <sector 0 info> | <sector 1 data> | ... <sector n-1 info>
    The required size of the buffer (whick must match the block size exactly) depends on the sector size of the flash device you are using.

    Note that the IOCTL writes only a single block to flash.
    You will need to call it for each block to program.

    Also note that the IOCTL does not handle bad blocks - the application is responsible for this (check GetLastError for ERROR_BAD_UNIT if the DeviceIoControl call fails).
    A sensible way to go about it would be to retry the write on the next flash block.
    The TI bootloader already handles bad blocks by skipping them and reading the data from the next block instead.

  • Hi Carsten,

    Thank you very much for the sample code and the explanations.  I have a much better understanding now.  I just have a few more questions for you.

    1 - For XLDR/Bootloader I can set req.dwBlock to 0 but I think for NK.bin, the block must not be 0 to start.  If I am correct, how do I know which block is the first one when flashing NK.bin?

    2 - What do you use for <sector # info > ?  Are they the same for both bootloader and nk.bin.

    I see in the boot loader, the sectorInfo is set as below.  Is that OK to use?

    // Prepare sector info
    memset(&sectorInfo, 0xFF, sizeof(sectorInfo));
    sectorInfo.bOEMReserved &= ~(OEM_BLOCK_READONLY|OEM_BLOCK_RESERVED);
    sectorInfo.dwReserved1 = 0;
    sectorInfo.wReserved2 = 0;

    3 - From the application, do you read in NK.nb0 or NK.bin?  Did you convert NK.bin to NK.nb0 during the download and also add sector info to the data?

    Again, I appreciate your help very much.

    Luan

  • Hi Luan,

    1 - For XLDR, and since you are using NAND flash, you should program four separate copies of XLDR, each in a separate block (i.e. blocks 0, 1, 2 and 3 should contain a copy of XLDR). The CPU will look for XLDR starting from block 0 and, if that fails for any reason, will try block 1, 2 and then 3 (this is documented in 25.4.7.2 in rev. T of the OMAP TRM).

    It follows then that, unless the BSP is configured in some unusual way, Eboot should be stored in block 4 onwards.

    As for NK it depends on how Eboot goes about loading NK, and you should probably take a look at the Eboot sources.

    Some BSPs store NK at a fixed offset, whereas others store NK immediately after Eboot.
    In the latter case this obviously means the location of NK varies depending on the size of Eboot.

    2 - We use the following for sector info:

    SectorInfo sectorInfo;
    memset(&sectorInfo, 0xff, sizeof(sectorInfo));
    sectorInfo.bOEMReserved = ~(OEM_BLOCK_RESERVED | OEM_BLOCK_READONLY);
    // sectorInfo.bBadBlock = 0xff; // 0 => bad sector, 0xff => good sector
    // sectorInfo.dwReserved1 = 0xffffffff;  // Used by flash disk driver for sector mapping
    // sectorInfo.wReserved2 = 0xffff;

    Values are the same for XLDR, Eboot and NK.

    The main thing is to ensure sectors are marked as reserved, because this will prevent the Windows CE flash driver from using the blocks to create a disk.

    3 - Our application reads NK.bin and converts to NK.nb0 on the fly.
    Sector info is then added to each buffer that is passed to the FMD through the ioctl.

    Accepting images in NK.bin format means we need to transfer less data via LAN when we do an update, but comes at the cost of added complexity in our application software running on the device.

    Best regards,
    Carsten