~aleteoryx/muditaos

5400c1861ec2494538a6c7011b84b04aaa4d4973 — Hubert Chrzaniuk 5 years ago b04f19b
[EGD-5014] Add eMMC block device API

Add PureOS wrapper for eMMC driver with support
for basic block device operations.
M image/user/db/settings_v2_002.sql => image/user/db/settings_v2_002.sql +1 -1
@@ 13,7 13,7 @@ INSERT OR IGNORE INTO settings_tab (path, value) VALUES
    ('gs_lock_pass_hash', '3333'),
    ('gs_lock_time', '30000'),
    ('gs_display_language', 'English'),
    ('gs_input_language', 'English');
    ('gs_input_language', 'English'),
    ('bt_state', '0'),
    ('bt_device_visibility', '0'),
    ('bt_device_name', 'PurePhone'),

M module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c => module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.c +3 -21
@@ 57,15 57,6 @@
inline static status_t MMC_SelectCard(mmc_card_t *card, bool isSelected);

/*!
 * @brief Wait write process complete.
 *
 * @param card Card descriptor.
 * @retval kStatus_Timeout Operation timeout.
 * @retval kStatus_Success Operate successfully.
 */
static status_t MMC_WaitWriteComplete(mmc_card_t *card);

/*!
 * @brief Send SET_BLOCK_COUNT command.
 *
 * @param card Card descriptor.


@@ 149,15 140,6 @@ static void MMC_DecodeCsd(mmc_card_t *card, uint32_t *rawCsd);
static void MMC_SetMaxFrequency(mmc_card_t *card);

/*!
 * @brief Set erase unit size of the card
 *
 * @param card Card descriptor.
 * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure Extended CSD failed.
 * @retval kStatus_Success Operate successfully.
 */
static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card);

/*!
 * @brief Send SWITCH command to set the specific byte in Extended CSD.
 *
 * Example:


@@ 524,7 506,7 @@ static status_t MMC_Transfer(mmc_card_t *card, SDMMCHOST_TRANSFER *content, uint
    return error;
}

static status_t MMC_WaitWriteComplete(mmc_card_t *card)
status_t MMC_WaitWriteComplete(mmc_card_t *card)
{
    assert(card);



@@ 825,8 807,8 @@ static void MMC_SetMaxFrequency(mmc_card_t *card)
    card->busClock_Hz = SDMMCHOST_SET_CARD_CLOCK(card->host.base, card->host.sourceClock_Hz, maxBusClock_Hz);
}

static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) __attribute__((used));
static status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card)
status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card) __attribute__((used));
status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card)
{
    assert(card);


M module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h => module-bsp/board/rt1051/bsp/eMMC/fsl_mmc.h +18 -0
@@ 338,6 338,24 @@ extern "C"
     */
    status_t MMC_SetGeneralPurposePartitioning(mmc_card_t *card, mmc_access_partition_t partition, uint32_t size);

    /*!
     * @brief Wait write process complete.
     *
     * @param card Card descriptor.
     * @retval kStatus_Timeout Operation timeout.
     * @retval kStatus_Success Operate successfully.
     */
    status_t MMC_WaitWriteComplete(mmc_card_t *card);

    /*!
     * @brief Set erase unit size of the card
     *
     * @param card Card descriptor.
     * @retval kStatus_SDMMC_ConfigureExtendedCsdFailed Configure Extended CSD failed.
     * @retval kStatus_Success Operate successfully.
     */
    status_t MMC_SetMaxEraseUnitSize(mmc_card_t *card);

/* @} */
#if defined(__cplusplus)
}

A module-vfs/board/rt1051/purefs/include/purefs/blkdev/disk_emmc.hpp => module-vfs/board/rt1051/purefs/include/purefs/blkdev/disk_emmc.hpp +42 -0
@@ 0,0 1,42 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <purefs/blkdev/disk.hpp>
#include <bsp/common.hpp>

#include "board/rt1051/bsp/eMMC/fsl_mmc.h"

#include <mutex.hpp>

#if !defined(TARGET_RT1051)
static_assert(false, "Unsupported target.");
#endif

namespace purefs::blkdev
{
    class disk_emmc final : public disk
    {
      public:
        static constexpr status_t statusBlkDevSuccess = 0;
        static constexpr status_t statusBlkDevFail    = -1;

        disk_emmc();

        auto probe(unsigned flags) -> int override;
        auto cleanup() -> int override;
        auto write(const void *buf, sector_t lba, std::size_t count) -> int override;
        auto read(void *buf, sector_t lba, std::size_t count) -> int override;
        auto sync() -> int override;
        auto status() const -> media_status override;
        auto get_info(info_type what) const -> scount_t override;
        auto erase(sector_t lba, std::size_t count) -> int override;

      private:
        status_t initStatus = kStatus_Success;

        mmc_card_t mmcCard;
        mutable cpp_freertos::MutexRecursive mutex;
    };
} // namespace purefs::blkdev

A module-vfs/board/rt1051/purefs/src/blkdev/disk_emmc.cpp => module-vfs/board/rt1051/purefs/src/blkdev/disk_emmc.cpp +130 -0
@@ 0,0 1,130 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/blkdev/disk_emmc.hpp>
#include <unistd.h>
#include <cstring>
#include <task.h>

namespace purefs::blkdev
{
    disk_emmc::disk_emmc()
    {
        mmcCard.busWidth                   = kMMC_DataBusWidth8bit;
        mmcCard.busTiming                  = kMMC_HighSpeedTiming;
        mmcCard.enablePreDefinedBlockCount = true;
        mmcCard.host.base                  = USDHC2;
        mmcCard.host.sourceClock_Hz        = GetPerphSourceClock(PerphClock_USDHC2);
    }

    auto disk_emmc::probe(unsigned int flags) -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        auto err = MMC_Init(&mmcCard);
        if (err != kStatus_Success) {
            initStatus = err;
            return initStatus;
        }
        err = MMC_SetMaxEraseUnitSize(&mmcCard);
        if (err != kStatus_Success) {
            initStatus = err;
            return initStatus;
        }
        return statusBlkDevSuccess;
    }

    auto disk_emmc::cleanup() -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard.isHostReady) {
            return statusBlkDevFail;
        }
        MMC_Deinit(&mmcCard);
        return statusBlkDevSuccess;
    }

    auto disk_emmc::write(const void *buf, sector_t lba, std::size_t count) -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard.isHostReady || buf == nullptr) {
            return statusBlkDevFail;
        }
        auto err = MMC_WriteBlocks(&mmcCard, static_cast<const uint8_t *>(buf), lba, count);
        if (err != kStatus_Success) {
            return err;
        }
        return statusBlkDevSuccess;
    }

    auto disk_emmc::erase(sector_t lba, std::size_t count) -> int
    {
        // temporarily commented out until erase is tested
        /* cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard.isHostReady) {
            return statusBlkDevFail;
        }

        auto err = MMC_EraseGroups(&mmcCard, lba, lba + count);
        if (err != kStatus_Success) {
            return err;
        } */
        return statusBlkDevSuccess;
    }
    auto disk_emmc::read(void *buf, sector_t lba, std::size_t count) -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard.isHostReady || buf == nullptr) {
            return statusBlkDevFail;
        }
        auto err = MMC_ReadBlocks(&mmcCard, static_cast<uint8_t *>(buf), lba, count);
        if (err != kStatus_Success) {
            return err;
        }
        return statusBlkDevSuccess;
    }
    auto disk_emmc::sync() -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard.isHostReady) {
            return statusBlkDevFail;
        }
        // Wait for the card's buffer to become empty
        while ((GET_SDMMCHOST_STATUS(mmcCard.host.base) & CARD_DATA0_STATUS_MASK) != CARD_DATA0_NOT_BUSY) {
            taskYIELD();
        }

        if (kStatus_Success != MMC_WaitWriteComplete(&mmcCard)) {
            return kStatus_SDMMC_WaitWriteCompleteFailed;
        }
        return statusBlkDevSuccess;
    }
    auto disk_emmc::status() const -> media_status
    {
        cpp_freertos::LockGuard lock(mutex);
        if (initStatus != kStatus_Success) {
            return media_status::error;
        }
        if (!mmcCard.isHostReady) {
            return media_status::uninit;
        }
        if ((mmcCard.csd.flags & kMMC_CsdPermanentWriteProtectFlag) ||
            (mmcCard.csd.flags & kMMC_CsdTemporaryWriteProtectFlag)) {
            return media_status::wprotect;
        }
        return media_status::healthly;
    }

    auto disk_emmc::get_info(info_type what) const -> scount_t
    {
        cpp_freertos::LockGuard lock(mutex);
        switch (what) {
        case info_type::sector_size:
            return mmcCard.blockSize;
        case info_type::sector_count:
            return mmcCard.userPartitionBlocks;
        case info_type::erase_block:
            return mmcCard.eraseGroupBlocks;
        }
        return -1;
    }
} // namespace purefs::blkdev

M module-vfs/board/rt1051/purefs/src/vfs_subsystem_internal.cpp => module-vfs/board/rt1051/purefs/src/vfs_subsystem_internal.cpp +2 -2
@@ 3,12 3,12 @@

#include <purefs/vfs_subsystem_internal.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/blkdev/disk_emmc.hpp>

namespace purefs::subsystem::internal
{
    auto create_default_block_device() -> std::shared_ptr<blkdev::disk>
    {
        // TODO: implement for rt1051
        return nullptr;
        return std::make_shared<purefs::blkdev::disk_emmc>();
    }
} // namespace purefs::subsystem::internal

M module-vfs/include/internal/purefs/blkdev/disk_handle.hpp => module-vfs/include/internal/purefs/blkdev/disk_handle.hpp +1 -1
@@ 30,7 30,7 @@ namespace purefs::blkdev::internal
        {
            return m_partition;
        }
        auto has_partition() const noexcept
        auto has_partition() const noexcept -> bool
        {
            return m_partition != no_parition;
        }

M module-vfs/src/newlib/vfs_io_syscalls.cpp => module-vfs/src/newlib/vfs_io_syscalls.cpp +1 -1
@@ 120,7 120,7 @@ namespace vfsn::internal::syscalls
        }
        const auto ret  = vfs->getcwd();
        const auto slen = ret.copy(buf, size);
        if (size < slen) {
        if (size >= slen) {
            buf[slen] = '\0';
        }
        return buf;

M module-vfs/src/purefs/blkdev/disk_manager.cpp => module-vfs/src/purefs/blkdev/disk_manager.cpp +2 -2
@@ 36,7 36,7 @@ namespace purefs::blkdev
        cpp_freertos::LockGuard _lck(*m_lock);
        const auto ret = m_dev_map.find(std::string(device_name));
        if (ret != std::end(m_dev_map)) {
            LOG_ERROR("Disc: %.*s already registered.", int(device_name.length()), device_name.data());
            LOG_ERROR("Disc: %s already registered.", std::string(device_name).c_str());
            return -EEXIST;
        }
        else {


@@ 54,7 54,7 @@ namespace purefs::blkdev
        cpp_freertos::LockGuard _lck(*m_lock);
        auto it = m_dev_map.find(std::string(device_name));
        if (it == std::end(m_dev_map)) {
            LOG_ERROR("Disc: %.*s doesn't exists in manager.", int(device_name.length()), device_name.data());
            LOG_ERROR("Disc: %s doesn't exists in manager.", std::string(device_name).c_str());
            return -ENOENT;
        }
        auto ret = it->second->cleanup();

M module-vfs/src/purefs/fs/filesystem.cpp => module-vfs/src/purefs/fs/filesystem.cpp +6 -6
@@ 36,7 36,7 @@ namespace purefs::fs
        cpp_freertos::LockGuard _lck(*m_lock);
        const auto it = m_fstypes.find(std::string(fsname));
        if (it != std::end(m_fstypes)) {
            LOG_ERROR("Disc: %.*s already registered.", int(fsname.length()), fsname.data());
            LOG_ERROR("Disc: %s already registered.", std::string(fsname).c_str());
            return -EEXIST;
        }
        else {


@@ 59,7 59,7 @@ namespace purefs::fs
            return -ENOENT;
        }
        if (it->second->mount_count() > 0) {
            LOG_ERROR("VFS: fileystem %.*s  is already used", int(fsname.length()), fsname.data());
            LOG_ERROR("VFS: fileystem %s  is already used", std::string(fsname).c_str());
            return -EBUSY;
        }
        m_fstypes.erase(it);


@@ 89,13 89,13 @@ namespace purefs::fs
                    return {};
                }
                else {
                    LOG_ERROR("VFS: mount point already exists %.*s", int(target.length()), target.data());
                    LOG_ERROR("VFS: mount point already exists %s", std::string(target).c_str());
                    return -EBUSY;
                }
            }
            const auto mpp = m_partitions.find(std::string(dev_or_part));
            if (mpp != std::end(m_partitions)) {
                LOG_ERROR("VFS: partition already used %.*s", int(dev_or_part.length()), dev_or_part.data());
                LOG_ERROR("VFS: partition already used %s", std::string(dev_or_part).c_str());
                return -EBUSY;
            }
            std::string filesystem_type;


@@ 111,7 111,7 @@ namespace purefs::fs
            }
            const auto vsi = m_fstypes.find(filesystem_type);
            if (vsi == std::end(m_fstypes)) {
                LOG_ERROR("VFS: requested filesystem %s not registered", filesystem_type.c_str());
                LOG_ERROR("VFS: requested filesystem %s not registered", std::string(fs_type).c_str());
                return -ENODEV;
            }
            // Trying to open disk or part by manager


@@ 138,7 138,7 @@ namespace purefs::fs
                }
            }
            else {
                LOG_ERROR("Device or partition %.*s doesn't exists", int(dev_or_part.size()), dev_or_part.data());
                LOG_ERROR("Device or partition %s doesn't exists", std::string(dev_or_part).c_str());
                return -ENXIO;
            }
        }

M module-vfs/src/purefs/fs/filesystem_syscalls.cpp => module-vfs/src/purefs/fs/filesystem_syscalls.cpp +29 -2
@@ 9,109 9,131 @@
#include <purefs/fs/thread_local_cwd.hpp>
#include <fcntl.h>

#include <mutex.hpp>

namespace purefs::fs
{
    auto filesystem::stat_vfs(std::string_view path, struct ::statvfs &stat) const noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::ro, &filesystem_operations::stat_vfs, path, stat);
    }

    auto filesystem::stat(std::string_view file, struct stat &st) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::ro, &filesystem_operations::stat, file, st);
    }

    auto filesystem::unlink(std::string_view name) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::rw, &filesystem_operations::unlink, name);
    }

    auto filesystem::mkdir(std::string_view path, int mode) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::rw, &filesystem_operations::mkdir, path, mode);
    }

    auto filesystem::ioctl(std::string_view path, int cmd, void *arg) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::ro, &filesystem_operations::ioctl, path, cmd, arg);
    }

    auto filesystem::utimens(std::string_view path, std::array<timespec, 2> &tv) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::ro, &filesystem_operations::utimens, path, tv);
    }

    auto filesystem::flock(int fd, int cmd) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::flock, fd, cmd);
    }

    auto filesystem::isatty(int fd) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::isatty, fd);
    }

    auto filesystem::chmod(std::string_view path, mode_t mode) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(iaccess::rw, &filesystem_operations::chmod, path, mode);
    }

    auto filesystem::write(int fd, const char *ptr, size_t len) noexcept -> ssize_t
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::write, fd, ptr, len);
    }

    auto filesystem::read(int fd, char *ptr, size_t len) noexcept -> ssize_t
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::read, fd, ptr, len);
    }

    auto filesystem::seek(int fd, off_t pos, int dir) noexcept -> off_t
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::seek, fd, pos, dir);
    }

    auto filesystem::fstat(int fd, struct stat &st) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::fstat, fd, st);
    }

    auto filesystem::ftruncate(int fd, off_t len) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::ftruncate, fd, len);
    }

    auto filesystem::fsync(int fd) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::fsync, fd);
    }

    auto filesystem::fchmod(int fd, mode_t mode) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::fchmod, fd, mode);
    }

    auto filesystem::symlink(std::string_view existing, std::string_view newlink) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops_same_mp(&filesystem_operations::symlink, existing, newlink);
    }

    auto filesystem::link(std::string_view existing, std::string_view newlink) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops_same_mp(&filesystem_operations::link, existing, newlink);
    }

    auto filesystem::rename(std::string_view oldname, std::string_view newname) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops_same_mp(&filesystem_operations::rename, oldname, newname);
    }

    auto filesystem::open(std::string_view path, int flags, int mode) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        const auto abspath     = absolute_path(path);
        auto [mountp, pathpos] = find_mount_point(abspath);
        if (!mountp) {
            LOG_ERROR("VFS: Unable to find mount point: %.*s", int(path.size()), path.data());
            LOG_ERROR("VFS: Unable to find mount point: %s", std::string(path).c_str());
            return -ENOENT;
        }
        auto fsops = mountp->fs_ops();


@@ 139,6 161,7 @@ namespace purefs::fs

    auto filesystem::close(int fd) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        auto ret = invoke_fops(&filesystem_operations::close, fd);
        if (!ret) {
            ret = (remove_filehandle(fd)) ? (0) : (-EBADF);


@@ 148,10 171,11 @@ namespace purefs::fs

    auto filesystem::diropen(std::string_view path) noexcept -> fsdir
    {
        cpp_freertos::LockGuard lock(*m_lock);
        const auto abspath     = absolute_path(path);
        auto [mountp, pathpos] = find_mount_point(abspath);
        if (!mountp) {
            LOG_ERROR("VFS: Unable to find mount point: %.*s", int(path.size()), path.data());
            LOG_ERROR("VFS: Unable to find mount point: %s", std::string(path).c_str());
            return std::make_shared<internal::directory_handle>(nullptr, -ENOENT);
        }
        auto fsops = mountp->fs_ops();


@@ 171,11 195,13 @@ namespace purefs::fs

    auto filesystem::dirreset(fsdir dirstate) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        return invoke_fops(&filesystem_operations::dirreset, dirstate);
    }

    auto filesystem::dirnext(fsdir dirstate, std::string &filename, struct stat &filestat) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        if (!dirstate) {
            LOG_ERROR("No directory handle");
            return -ENXIO;


@@ 185,6 211,7 @@ namespace purefs::fs

    auto filesystem::dirclose(fsdir dirstate) noexcept -> int
    {
        cpp_freertos::LockGuard lock(*m_lock);
        if (!dirstate) {
            LOG_ERROR("No directory handle");
            return -ENXIO;

M module-vfs/targets/Target_RT1051.cmake => module-vfs/targets/Target_RT1051.cmake +5 -3
@@ 1,12 1,14 @@
set(BOARD_SOURCES ${BOARD_SOURCES}
        src/newlib/vfs_io_syscalls.cpp
        board/rt1051/purefs/src/fs/thread_local_cwd.cpp
        board/rt1051/purefs/src/vfs_subsystem_internal.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/purefs/src/blkdev/disk_emmc.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/purefs/src/fs/thread_local_cwd.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/purefs/src/vfs_subsystem_internal.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/src/newlib/vfs_io_syscalls.cpp
        CACHE INTERNAL ""
)

set(BOARD_DIR_INCLUDES ${BOARD_DIR_INCLUDES}
    ${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051
    ${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/purefs/include/
    CACHE INTERNAL ""
)