Exemple #1
0
/** @brief Compare the contents of two buffers.

    @param pMem1    The first buffer to compare.
    @param pMem2    The second buffer to compare.
    @param ulLen    The length to compare.

    @return Zero if the two buffers are the same, otherwise nonzero.
*/
static int32_t RedMemCmpUnchecked(
    const void     *pMem1,
    const void     *pMem2,
    uint32_t        ulLen)
{
    const uint8_t  *pbMem1 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem1);
    const uint8_t  *pbMem2 = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMem2);
    uint32_t        ulIdx = 0U;
    int32_t         lResult;

    while((ulIdx < ulLen) && (pbMem1[ulIdx] == pbMem2[ulIdx]))
    {
        ulIdx++;
    }

    if(ulIdx == ulLen)
    {
        lResult = 0;
    }
    else if(pbMem1[ulIdx] > pbMem2[ulIdx])
    {
        lResult = 1;
    }
    else
    {
        lResult = -1;
    }

    return lResult;
}
Exemple #2
0
/** @brief Write sectors to a disk.

    @param bVolNum          The volume number of the volume whose block device
                            is being written to.
    @param ullSectorStart   The starting sector number.
    @param ulSectorCount    The number of sectors to write.
    @param pBuffer          The buffer from which to write the sector data.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0   Operation was successful.
*/
static REDSTATUS DiskWrite(
    uint8_t         bVolNum,
    uint64_t        ullSectorStart,
    uint32_t        ulSectorCount,
    const void     *pBuffer)
{
    REDSTATUS       ret = 0;
    uint32_t        ulSectorIdx = 0U;
    uint32_t        ulSectorSize = gaRedVolConf[bVolNum].ulSectorSize;
    const uint8_t  *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);

    while(ulSectorIdx < ulSectorCount)
    {
        uint32_t    ulTransfer = REDMIN(ulSectorCount - ulSectorIdx, MAX_SECTOR_TRANSFER);
        Ctrl_status cs;

        cs = sd_mmc_ram_2_mem_multi(bVolNum, (uint32_t)(ullSectorStart + ulSectorIdx),
                                    (uint16_t)ulTransfer, &pbBuffer[ulSectorIdx * ulSectorSize]);
        if(cs != CTRL_GOOD)
        {
            ret = -RED_EIO;
            break;
        }

        ulSectorIdx += ulTransfer;
    }

    return ret;
}
Exemple #3
0
/** @brief Write sectors to a disk.

    @param bVolNum          The volume number of the volume whose block device
                            is being written to.
    @param ullSectorStart   The starting sector number.
    @param ulSectorCount    The number of sectors to write.
    @param pBuffer          The buffer from which to write the sector data.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS DiskWrite(
    uint8_t         bVolNum,
    uint64_t        ullSectorStart,
    uint32_t        ulSectorCount,
    const void     *pBuffer)
{
    REDSTATUS       ret = 0;
    uint32_t        ulSectorIdx = 0U;
    uint32_t        ulSectorSize = gaRedVolConf[bVolNum].ulSectorSize;
    const uint8_t  *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);

    while(ulSectorIdx < ulSectorCount)
    {
        uint32_t    ulTransfer = REDMIN(ulSectorCount - ulSectorIdx, MAX_SECTOR_TRANSFER);
        DRESULT     result;

        result = disk_write(bVolNum, &pbBuffer[ulSectorIdx * ulSectorSize], (DWORD)(ullSectorStart + ulSectorIdx), (BYTE)ulTransfer);
        if(result != RES_OK)
        {
            ret = -RED_EIO;
            break;
        }

        ulSectorIdx += ulTransfer;
    }

    return ret;
}
Exemple #4
0
/** @brief Determine whether the metaroot is valid.

    @param pMR                  The metaroot buffer.
    @param pfSectorCRCIsValid   Populated with whether the first sector of the
                                metaroot buffer is valid.

    @return Whether the metaroot is valid.

    @retval true    The metaroot buffer is valid.
    @retval false   The metaroot buffer is invalid.
*/
static bool MetarootIsValid(
    METAROOT   *pMR,
    bool       *pfSectorCRCIsValid)
{
    bool        fRet = false;

    if(pfSectorCRCIsValid == NULL)
    {
        REDERROR();
    }
    else if(pMR == NULL)
    {
        REDERROR();
        *pfSectorCRCIsValid = false;
    }
  #ifdef REDCONF_ENDIAN_SWAP
    else if(RedRev32(pMR->hdr.ulSignature) != META_SIG_METAROOT)
  #else
    else if(pMR->hdr.ulSignature != META_SIG_METAROOT)
  #endif
    {
        *pfSectorCRCIsValid = false;
    }
    else
    {
        const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pMR);
        uint32_t        ulSectorCRC = pMR->ulSectorCRC;
        uint32_t        ulCRC;

      #ifdef REDCONF_ENDIAN_SWAP
        ulSectorCRC = RedRev32(ulSectorCRC);
      #endif

        /*  The sector CRC was zero when the CRC was computed during the
            transaction, so it must be zero here.
        */
        pMR->ulSectorCRC = 0U;

        ulCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);

        fRet = ulCRC == ulSectorCRC;
        *pfSectorCRCIsValid = fRet;

        if(fRet)
        {
            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                ulCRC = RedCrc32Update(ulCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }

          #ifdef REDCONF_ENDIAN_SWAP
            ulCRC = RedRev32(ulCRC);
          #endif

            fRet = ulCRC == pMR->hdr.ulCRC;
        }
    }

    return fRet;
}
Exemple #5
0
/** @brief Write sectors to a disk.

    @param bVolNum          The volume number of the volume whose block device
                            is being written to.
    @param ullSectorStart   The starting sector number.
    @param ulSectorCount    The number of sectors to write.
    @param pBuffer          The buffer from which to write the sector data.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EINVAL The block device is not open.
    @retval -RED_EIO    A disk I/O error occurred.
*/
static REDSTATUS DiskWrite(
    uint8_t     bVolNum,
    uint64_t    ullSectorStart,
    uint32_t    ulSectorCount,
    const void *pBuffer)
{
    REDSTATUS   ret = 0;
    F_DRIVER   *pDriver = gapFDriver[bVolNum];

    if(pDriver == NULL) {
        ret = -RED_EINVAL;
    } else {
        const uint8_t  *pbBuffer = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pBuffer);
        uint32_t        ulSectorSize = gaRedVolConf[bVolNum].ulSectorSize;
        uint32_t        ulSectorIdx;
        int             iErr;

        for(ulSectorIdx = 0U; ulSectorIdx < ulSectorCount; ulSectorIdx++) {
            /*  We have to cast pbBuffer to non-const since the writesector
                prototype is flawed, using a non-const pointer for the buffer.
            */
            iErr = pDriver->writesector(pDriver, CAST_AWAY_CONST(uint8_t, &pbBuffer[ulSectorIdx * ulSectorSize]),
                                        CAST_ULONG(ullSectorStart + ulSectorCount));
            if(iErr != 0) {
                ret = -RED_EIO;
                break;
            }
        }
    }

    return ret;
}
Exemple #6
0
/** @brief Copy memory from one address to another.

    This function should only be called from RedMemCpy().

    @param pDest    The destination buffer.
    @param pSrc     The source buffer.
    @param ulLen    The number of bytes to copy.
*/
static void RedMemCpyUnchecked(
    void           *pDest,
    const void     *pSrc,
    uint32_t        ulLen)
{
    uint8_t        *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest);
    const uint8_t  *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc);
    uint32_t        ulIdx;

    for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
    {
        pbDest[ulIdx] = pbSrc[ulIdx];
    }
}
Exemple #7
0
/** @brief Move memory from one address to another.

    This function should only be called from RedMemMove().

    @param pDest    The destination buffer.
    @param pSrc     The source buffer.
    @param ulLen    The number of bytes to copy.
*/
static void RedMemMoveUnchecked(
    void           *pDest,
    const void     *pSrc,
    uint32_t        ulLen)
{
    uint8_t        *pbDest = CAST_VOID_PTR_TO_UINT8_PTR(pDest);
    const uint8_t  *pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR(pSrc);
    uint32_t        ulIdx;

    if(MEMMOVE_MUST_COPY_FORWARD(pbDest, pbSrc))
    {
        /*  If the destination is lower than the source with overlapping memory
            regions, we must copy from start to end in order to copy the memory
            correctly.

            Don't use RedMemCpy() to do this.  It is possible that RedMemCpy()
            has been replaced (even though this function has not been replaced)
            with an implementation that cannot handle any kind of buffer
            overlap.
        */
        for(ulIdx = 0U; ulIdx < ulLen; ulIdx++)
        {
            pbDest[ulIdx] = pbSrc[ulIdx];
        }
    }
    else
    {
        ulIdx = ulLen;

        while(ulIdx > 0U)
        {
            ulIdx--;
            pbDest[ulIdx] = pbSrc[ulIdx];
        }
    }
}
Exemple #8
0
/** @brief Commit a transaction point.

    @return A negated ::REDSTATUS code indicating the operation result.

    @retval 0           Operation was successful.
    @retval -RED_EIO    A disk I/O error occurred.
*/
REDSTATUS RedVolTransact(void)
{
    REDSTATUS ret = 0;

    REDASSERT(!gpRedVolume->fReadOnly); /* Should be checked by caller. */

    if(gpRedCoreVol->fBranched)
    {
        gpRedMR->ulFreeBlocks += gpRedCoreVol->ulAlmostFreeBlocks;
        gpRedCoreVol->ulAlmostFreeBlocks = 0U;

        ret = RedBufferFlush(0U, gpRedVolume->ulBlockCount);

        if(ret == 0)
        {
            gpRedMR->hdr.ulSignature = META_SIG_METAROOT;
            gpRedMR->hdr.ullSequence = gpRedVolume->ullSequence;

            ret = RedVolSeqNumIncrement();
        }

        if(ret == 0)
        {
            const uint8_t  *pbMR = CAST_VOID_PTR_TO_CONST_UINT8_PTR(gpRedMR);
            uint32_t        ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif

            gpRedMR->ulSectorCRC = 0U;

            ulSectorCRC = RedCrc32Update(0U, &pbMR[8U], gpRedVolConf->ulSectorSize - 8U);

            if(gpRedVolConf->ulSectorSize < REDCONF_BLOCK_SIZE)
            {
                gpRedMR->hdr.ulCRC = RedCrc32Update(ulSectorCRC, &pbMR[gpRedVolConf->ulSectorSize], REDCONF_BLOCK_SIZE - gpRedVolConf->ulSectorSize);
            }
            else
            {
                gpRedMR->hdr.ulCRC = ulSectorCRC;
            }

            gpRedMR->ulSectorCRC = ulSectorCRC;

          #ifdef REDCONF_ENDIAN_SWAP
            gpRedMR->hdr.ulCRC = RedRev32(gpRedMR->hdr.ulCRC);
            gpRedMR->ulSectorCRC = RedRev32(gpRedMR->ulSectorCRC);
          #endif

            /*  Flush the block device before writing the metaroot, so that all
                previously written blocks are guaranteed to be on the media before
                the metaroot is written.  Otherwise, if the block device reorders
                the writes, the metaroot could reach the media before metadata it
                points at, creating a window for disk corruption if power is lost.
            */
            ret = RedIoFlush(gbRedVolNum);
        }

        if(ret == 0)
        {
            ret = RedIoWrite(gbRedVolNum, BLOCK_NUM_FIRST_METAROOT + gpRedCoreVol->bCurMR, 1U, gpRedMR);

          #ifdef REDCONF_ENDIAN_SWAP
            MetaRootEndianSwap(gpRedMR);
          #endif
        }

        /*  Flush the block device to force the metaroot write to the media.  This
            guarantees the transaction point is really complete before we return.
        */
        if(ret == 0)
        {
            ret = RedIoFlush(gbRedVolNum);
        }

        /*  Toggle to the other metaroot buffer.  The working state and committed
            state metaroot buffers exchange places.
        */
        if(ret == 0)
        {
            uint8_t bNextMR = 1U - gpRedCoreVol->bCurMR;

            gpRedCoreVol->aMR[bNextMR] = *gpRedMR;
            gpRedCoreVol->bCurMR = bNextMR;

            gpRedMR = &gpRedCoreVol->aMR[gpRedCoreVol->bCurMR];

            gpRedCoreVol->fBranched = false;
        }

        CRITICAL_ASSERT(ret == 0);
    }

    return ret;
}