~aleteoryx/muditaos

b04b66e8e0f2bf32eab00eae02238be411e63189 — Lucjan Bryndza 4 years ago 37e2e33
[EGD-6522] Add EEPROM emulation in the emulator

Add possibility to emulate eeprom in the linux emulator
M enabled_unittests => enabled_unittests +1 -0
@@ 433,6 433,7 @@ TESTS_LIST["catch2-vfs-disk"]="
    Boundary checks for partitions;
    Disk sectors out of range for partition;
    Alternative partitions in the disk manager;
    Disk manager EEPROM emulation;
"
#---------
TESTS_LIST["catch2-vfs-littlefs"]="

M module-vfs/board/linux/purefs/include/purefs/blkdev/disk_image.hpp => module-vfs/board/linux/purefs/include/purefs/blkdev/disk_image.hpp +8 -8
@@ 5,20 5,17 @@

#include <purefs/blkdev/disk.hpp>
#include <mutex>
#include <array>
#include <vector>

namespace purefs::blkdev
{
    class disk_image final : public disk
    {
        static constexpr auto sector_size = 512UL;
        static constexpr auto invalid_fd      = -1;
        static constexpr auto syspart_count   = 8U;
        static constexpr auto syspart_size    = 256UL * 1024UL * 1024UL;
        static constexpr auto syspart_sectors = syspart_size / sector_size;
        static constexpr auto syspart_size    = 32 * 1024UL * 1024UL;

      public:
        disk_image(std::string_view image_filename);
        explicit disk_image(std::string_view image_filename, std::size_t sector_size = 512, hwpart_t num_parts = 8);
        virtual ~disk_image()
        {}



@@ 35,9 32,12 @@ namespace purefs::blkdev
        auto open_and_truncate(hwpart_t hwpart) -> int;

      private:
        std::array<int, syspart_count> m_filedes;
        std::array<unsigned long, syspart_count> m_sectors;
        std::vector<int> m_filedes;
        std::vector<std::size_t> m_sectors;
        const std::string m_image_name;
        const std::size_t m_sector_size;
        const std::size_t m_syspart_sectors;
        const hwpart_t m_sysparts;
        mutable std::recursive_mutex m_mtx;
    };
} // namespace purefs::blkdev

M module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp => module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp +21 -16
@@ 10,10 10,15 @@
namespace purefs::blkdev
{

    disk_image::disk_image(std::string_view image_filename) : m_image_name(image_filename)
    disk_image::disk_image(std::string_view image_filename, std::size_t sector_size, hwpart_t num_parts)
        : m_image_name(image_filename), m_sector_size(sector_size), m_syspart_sectors(syspart_size / sector_size),
          m_sysparts(num_parts)
    {
        m_filedes.fill(invalid_fd);
        std::fill(m_sectors.begin() + 1, m_sectors.end(), syspart_sectors);
        if (num_parts < 1) {
            throw std::range_error("Number of partitions out of range");
        }
        m_filedes.resize(num_parts, invalid_fd);
        m_sectors.resize(num_parts, m_syspart_sectors);
        m_sectors[0] = 0;
    }



@@ 28,8 33,8 @@ namespace purefs::blkdev
        if (ret < 0) {
            return -errno;
        }
        m_sectors[0] = fst.st_size / sector_size;
        return fst.st_size % sector_size;
        m_sectors[0] = fst.st_size / m_sector_size;
        return fst.st_size % m_sector_size;
    }

    auto disk_image::cleanup() -> int


@@ 57,11 62,11 @@ namespace purefs::blkdev
        if (err) {
            return err;
        }
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(sector_size), SEEK_SET);
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(m_sector_size), SEEK_SET);
        if (offs < 0) {
            return offs;
        }
        auto to_write = count * sector_size;
        auto to_write = count * m_sector_size;
        auto buf_b    = reinterpret_cast<const uint8_t *>(buf);
        do {
            auto ret = ::write(m_filedes[hwpart], buf_b, to_write);


@@ 76,8 81,8 @@ namespace purefs::blkdev

    auto disk_image::erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        std::unique_ptr<char[]> buf(new char[count * sector_size]);
        std::memset(buf.get(), 0xff, count * sector_size);
        std::unique_ptr<char[]> buf(new char[count * m_sector_size]);
        std::memset(buf.get(), 0xff, count * m_sector_size);
        return write(buf.get(), lba, count, hwpart);
    }



@@ 91,11 96,11 @@ namespace purefs::blkdev
        if (err) {
            return err;
        }
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(sector_size), SEEK_SET);
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(m_sector_size), SEEK_SET);
        if (offs < 0) {
            return offs;
        }
        auto to_read = count * sector_size;
        auto to_read = count * m_sector_size;
        auto buf_b   = reinterpret_cast<uint8_t *>(buf);
        do {
            auto ret = ::read(m_filedes[hwpart], buf_b, to_read);


@@ 135,12 140,12 @@ namespace purefs::blkdev
    auto disk_image::get_info(info_type what, hwpart_t hwpart) const -> scount_t
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        if (hwpart >= syspart_count) {
        if (hwpart >= m_sysparts) {
            return -ERANGE;
        }
        switch (what) {
        case info_type::sector_size:
            return sector_size;
            return m_sector_size;
        case info_type::sector_count:
            return m_sectors[hwpart];
        case info_type::erase_block:


@@ 151,12 156,12 @@ namespace purefs::blkdev

    auto disk_image::range_valid(sector_t lba, std::size_t count, hwpart_t hwpart) const -> bool
    {
        return (hwpart < syspart_count) && (lba < m_sectors[hwpart]) && ((lba + count) < m_sectors[hwpart]);
        return (hwpart < m_sysparts) && (lba < m_sectors[hwpart]) && ((lba + count) <= m_sectors[hwpart]);
    }

    auto disk_image::disk_image::open_and_truncate(hwpart_t hwpart) -> int
    {
        if (hwpart >= syspart_count) {
        if (hwpart >= m_sysparts) {
            return -ERANGE;
        }
        if (hwpart == 0 || m_filedes[hwpart] > 0) {


@@ 173,7 178,7 @@ namespace purefs::blkdev
        if (ret < 0) {
            return -errno;
        }
        if (static_cast<unsigned long>(fst.st_size) < m_sectors[hwpart] * sector_size) {
        if (static_cast<unsigned long>(fst.st_size) < m_sectors[hwpart] * m_sector_size) {
            ret = ::ftruncate(m_filedes[hwpart], syspart_size);
            if (ret < 0) {
                return ret;

M module-vfs/board/linux/purefs/src/vfs_subsystem_internal.cpp => module-vfs/board/linux/purefs/src/vfs_subsystem_internal.cpp +8 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/vfs_subsystem_internal.hpp>


@@ 10,9 10,16 @@ namespace purefs::subsystem::internal
    namespace
    {
        constexpr auto disk_image_name = "PurePhone.img";
        constexpr auto eeprom_image_name          = "eeprom.img";
        static constexpr auto eeprom_sector_size  = 64;
        static constexpr auto eeprom_num_sysparts = 1;
    }
    auto create_default_block_device() -> std::shared_ptr<blkdev::disk>
    {
        return std::make_shared<blkdev::disk_image>(disk_image_name);
    }
    auto create_default_nvm_device() -> std::shared_ptr<blkdev::disk>
    {
        return std::make_shared<blkdev::disk_image>(eeprom_image_name, eeprom_sector_size, eeprom_num_sysparts);
    }
} // namespace purefs::subsystem::internal

M module-vfs/board/rt1051/purefs/src/vfs_subsystem_internal.cpp => module-vfs/board/rt1051/purefs/src/vfs_subsystem_internal.cpp +5 -0
@@ 11,4 11,9 @@ namespace purefs::subsystem::internal
    {
        return std::make_shared<purefs::blkdev::disk_emmc>();
    }

    auto create_default_nvm_device() -> std::shared_ptr<blkdev::disk>
    {
        return {};
    }
} // namespace purefs::subsystem::internal

M module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp => module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp +2 -1
@@ 18,6 18,7 @@
#include <fcntl.h>
#include <errno.h>
#include <cstring>
#include <algorithm>
#include <sys/stat.h>

namespace


@@ 127,13 128,13 @@ namespace
        }
        cfg->block_cycles    = 512;
        cfg->block_count     = 0; // Read later from super block
        cfg->lookahead_size  = 131072;
        const auto total_siz = uint64_t(sector_size) * uint64_t(part_sectors_count);
        if (total_siz % cfg->block_size) {
            LOG_ERROR("Block size doesn't match partition size");
            return -ERANGE;
        }
        cfg->block_count = total_siz / cfg->block_size - 1;
        cfg->lookahead_size = std::min<lfs_size_t>(131072, cfg->block_count);
        cfg->read_size  = cfg->block_size;
        cfg->prog_size  = cfg->block_size;
        cfg->cache_size = cfg->block_size;

M module-vfs/include/internal/purefs/vfs_subsystem_internal.hpp => module-vfs/include/internal/purefs/vfs_subsystem_internal.hpp +2 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 12,4 12,5 @@ namespace purefs::blkdev
namespace purefs::subsystem::internal
{
    auto create_default_block_device() -> std::shared_ptr<blkdev::disk>;
    auto create_default_nvm_device() -> std::shared_ptr<blkdev::disk>;
}

M module-vfs/include/user/purefs/blkdev/defs.hpp => module-vfs/include/user/purefs/blkdev/defs.hpp +9 -0
@@ 48,4 48,13 @@ namespace purefs::blkdev
        force_suspend, //! Device is in force suspend state
        power_off      //! Device is in poweroff state
    };

    //! Disk manager flags
    struct flags
    {
        enum _flags
        {
            no_parts_scan = 0x1 //! Don't scan partitions on disc
        };
    };
} // namespace purefs::blkdev

M module-vfs/src/purefs/blkdev/disk_manager.cpp => module-vfs/src/purefs/blkdev/disk_manager.cpp +8 -1
@@ 47,7 47,14 @@ namespace purefs::blkdev
                return ret;
            }
            const auto it = m_dev_map.emplace(std::make_pair(device_name, disk));
            return reread_partitions(std::make_shared<internal::disk_handle>(disk, it.first->first));
            if (flags & flags::no_parts_scan) {
                disk->clear_partitions();
                return 0;
            }
            else {
                ret = reread_partitions(std::make_shared<internal::disk_handle>(disk, it.first->first));
                return ret;
            }
        }
    }
    auto disk_manager::unregister_device(std::string_view device_name) -> int

M module-vfs/src/purefs/blkdev/partition_parser.cpp => module-vfs/src/purefs/blkdev/partition_parser.cpp +5 -0
@@ 28,6 28,7 @@ namespace purefs::blkdev::internal
            constexpr auto reserved_sect      = 0x00e;
            constexpr auto number_of_fats     = 0x010;
            constexpr auto num_parts          = 4;
            constexpr auto min_sector_size    = 512;
        } // namespace
    }     // namespace defs
    namespace


@@ 58,6 59,10 @@ namespace purefs::blkdev::internal
        if (ret < 0) {
            return ret;
        }
        if (sect_size < defs::min_sector_size) {
            LOG_ERROR("Unable to scan partition when sector size < 512");
            return -ENXIO;
        }
        // Check initial signature
        if ((mbr_sect[defs::mbr_signature_offs] != 0x55) && (mbr_sect[defs::mbr_signature_offs + 1] != 0xAA)) {
            LOG_ERROR("Unable to find valid partition signature");

M module-vfs/tests/unittest_disk_manager.cpp => module-vfs/tests/unittest_disk_manager.cpp +33 -1
@@ 4,6 4,7 @@
#include <catch2/catch.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/blkdev/disk_image.hpp>
#include <filesystem>

namespace
{


@@ 11,7 12,9 @@ namespace
    constexpr auto part_disk_image     = "test_disk.img";
    constexpr auto part_disk_image_ext = "test_disk_ext.img";
    constexpr auto part_disk_image_bad = "test_disk_bad.img";
    constexpr auto eeprom_image        = "test_eeprom.bin";
} // namespace

TEST_CASE("Registering and unregistering device")
{
    using namespace purefs;


@@ 117,7 120,7 @@ TEST_CASE("Alternative partitions in the disk manager")
    REQUIRE(sect_size > 0);
    REQUIRE(sect_size == sect_size1);
    const auto sect_count = dm.get_info("emmc0sys1", blkdev::info_type::sector_count);
    REQUIRE(sect_count == (256L * 1024L * 1024L) / sect_size);
    REQUIRE(sect_count == (32 * 1024L * 1024L) / sect_size);
    const auto sect_count1 = dm.get_info("emmc0", blkdev::info_type::sector_count);
    REQUIRE(sect_count1 > sect_count);
    std::vector<char> buf1(sect_size, 0);


@@ 136,6 139,35 @@ TEST_CASE("Alternative partitions in the disk manager")
    REQUIRE(buf1 == buf2);
}

TEST_CASE("Disk manager EEPROM emulation")
{
    static constexpr auto eeprom_size        = 32768;
    static constexpr auto eeprom_sector_size = 64;

    using namespace purefs;
    std::ofstream ofc(eeprom_image);
    ofc.close();
    std::filesystem::resize_file(eeprom_image, eeprom_size);
    blkdev::disk_manager dm;
    auto disk = std::make_shared<blkdev::disk_image>(eeprom_image, eeprom_sector_size, 1);
    REQUIRE(disk);
    REQUIRE(dm.register_device(disk, "nvrom0", blkdev::flags::no_parts_scan) == 0);
    const auto sect_size  = dm.get_info("nvrom0", blkdev::info_type::sector_size);
    const auto sect_count = dm.get_info("nvrom0", blkdev::info_type::sector_count);
    REQUIRE(sect_size == eeprom_sector_size);
    REQUIRE(sect_count == eeprom_size / sect_size);
    std::vector<char> buf_in1(sect_size, 0xAA);
    std::vector<char> buf_in2(sect_size, 0xBB);
    REQUIRE(dm.write("nvrom0", buf_in1.data(), 0, 1) == 0);
    REQUIRE(dm.write("nvrom0", buf_in2.data(), sect_count - 1, 1) == 0);
    std::vector<char> buf_out1(sect_size);
    std::vector<char> buf_out2(sect_size);
    REQUIRE(dm.read("nvrom0", buf_out1.data(), 0, 1) == 0);
    REQUIRE(dm.read("nvrom0", buf_out2.data(), sect_count - 1, 1) == 0);
    REQUIRE(buf_in1 == buf_out1);
    REQUIRE(buf_in2 == buf_out2);
}

TEST_CASE("Null pointer passed to disk manager functions")
{
    using namespace purefs;