M board/linux/libiosyscalls/src/syscalls_posix.cpp => board/linux/libiosyscalls/src/syscalls_posix.cpp +1 -1
@@ 626,7 626,7 @@ extern "C"
{
if (vfs::redirect_to_image(dir)) {
TRACE_SYSCALLN("(%s, %s, %s, %08lx, %p) -> VFS", special_file, dir, fstype, rwflag, data);
- return vfs::invoke_fs(&fs::mount, special_file, dir, fstype, rwflag);
+ return vfs::invoke_fs(&fs::mount, special_file, dir, fstype, rwflag, data);
}
else {
TRACE_SYSCALLN("(%s, %s, %s, %08lx,%p) -> linux fs", special_file, dir, fstype, rwflag, data);
M host-tools/genlittlefs/mklfs.c => host-tools/genlittlefs/mklfs.c +6 -0
@@ 291,6 291,12 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
free(parts);
+ if (write_partition_bootunit(lopts.dst_image, lopts.partition_num, lopts.block_size)) {
+ perror("Unable to write bootunit");
+ free(lopts.src_dirs);
+ lfs_ioaccess_close(ioctx);
+ return EXIT_FAILURE;
+ }
}
else if (lopts.mode == littlefs_opts_file) {
int fds = open(lopts.dst_image, O_CREAT | O_WRONLY, 0644);
M host-tools/genlittlefs/parse_partitions.c => host-tools/genlittlefs/parse_partitions.c +51 -0
@@ 5,8 5,11 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
static const size_t sector_size = 512;
+static const size_t part_offset = 446;
+static const size_t part_size = 16;
struct partition *find_partitions(const char *filename, part_type_t ptype, size_t *nelems)
{
@@ 61,3 64,51 @@ void print_partitions(const struct partition *part, size_t nparts)
part[s].end / 1024);
}
}
+
+static inline unsigned calculate_shift(uint32_t v)
+{
+
+ static const int mult_bruijn_bit_position[32] = {0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
+
+ v |= v >> 1; // first round down to one less than a power of 2
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+
+ return mult_bruijn_bit_position[(uint32_t)(v * 0x07C4ACDDU) >> 27];
+}
+
+int write_partition_bootunit(const char *filename, int part_num, uint32_t block_size)
+{
+ if (!filename) {
+ errno = EINVAL;
+ return -1;
+ }
+ const uint8_t boot = calculate_shift(block_size);
+ const loff_t fil_offs = part_offset + (part_num - 1) * part_size;
+ FILE *fil = fopen(filename, "r+");
+ if (!fil) {
+ return -1;
+ }
+ if (fseek(fil, fil_offs, SEEK_SET) < 0) {
+ fclose(fil);
+ return -1;
+ }
+ uint8_t boot_rd;
+ if (fread(&boot_rd, sizeof boot_rd, 1, fil) != 1) {
+ fclose(fil);
+ return -1;
+ }
+ if (fseek(fil, fil_offs, SEEK_SET) < 0) {
+ fclose(fil);
+ return -1;
+ }
+ uint8_t boot_wr = (boot_rd & 0x80) | (boot & 0x7f);
+ if (fwrite(&boot_wr, sizeof boot_wr, 1, fil) != 1) {
+ fclose(fil);
+ return -1;
+ }
+ return fclose(fil);
+}
M host-tools/genlittlefs/parse_partitions.h => host-tools/genlittlefs/parse_partitions.h +4 -0
@@ 3,6 3,8 @@
#pragma once
#include <stddef.h>
+#include <stdint.h>
+#include <sys/types.h>
typedef int part_type_t;
@@ 22,3 24,5 @@ struct partition *find_partitions(const char *filename, part_type_t ptype, size_
__attribute__((nonnull(1, 3)));
void print_partitions(const struct partition *part, size_t nparts);
+
+int write_partition_bootunit(const char *filename, int part_num, uint32_t block_size);
M module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp +1 -1
@@ 22,7 22,7 @@ namespace purefs::fs::drivers
*/
auto mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh, std::string_view path, unsigned flags)
-> fsmount override;
- auto mount(fsmount mnt) noexcept -> int override;
+ auto mount(fsmount mnt, const void *data) noexcept -> int override;
auto umount(fsmount mnt) noexcept -> int override;
auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int override;
M module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp +1 -1
@@ 16,7 16,7 @@ namespace purefs::fs::drivers
private:
auto mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh, std::string_view path, unsigned flags)
-> fsmount override;
- auto mount(fsmount mnt) noexcept -> int override;
+ auto mount(fsmount mnt, const void *data) noexcept -> int override;
auto umount(fsmount mnt) noexcept -> int override;
auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int override;
M module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp => module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp +18 -8
@@ 112,11 112,21 @@ namespace
st.st_mode = translate_attrib_to_st_mode(fs.type, readOnly);
}
- [[gnu::nonnull(1)]] int setup_lfs_config(lfs_config *cfg, size_t sector_size, size_t part_sectors_count)
+ [[gnu::nonnull(1)]] int setup_lfs_config(lfs_config *cfg,
+ size_t sector_size,
+ size_t part_sectors_count,
+ const void *data)
{
- cfg->block_cycles = 512;
- cfg->block_size = c_lfs_block_size;
- cfg->block_count = 0; // Read later from super block
+ if (data) {
+ // NOTE: block size from mount param
+ cfg->block_size = *(reinterpret_cast<const uint32_t *>(data));
+ }
+ else {
+ cfg->block_size = c_lfs_block_size;
+ LOG_WARN("LFS: mount block size not specified using default value");
+ }
+ 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) {
@@ 127,7 137,7 @@ namespace
cfg->read_size = cfg->block_size;
cfg->prog_size = cfg->block_size;
cfg->cache_size = cfg->block_size;
- LOG_INFO("LFS: block_count %u sector_size %u", unsigned(cfg->block_count), unsigned(cfg->block_size));
+ LOG_INFO("LFS: block count %u block size %u", unsigned(cfg->block_count), unsigned(cfg->block_size));
return 0;
}
@@ 207,7 217,7 @@ namespace purefs::fs::drivers
return std::make_shared<mount_point_littlefs>(diskh, path, flags, shared_from_this());
}
- auto filesystem_littlefs::mount(fsmount mnt) noexcept -> int
+ auto filesystem_littlefs::mount(fsmount mnt, const void *data) noexcept -> int
{
auto disk = mnt->disk();
if (!disk) {
@@ 232,7 242,7 @@ namespace purefs::fs::drivers
else {
auto sect_count = diskmm->get_info(disk, blkdev::info_type::sector_count);
if (sect_count > 0) {
- err = setup_lfs_config(vmnt->lfs_config(), ssize, sect_count);
+ err = setup_lfs_config(vmnt->lfs_config(), ssize, sect_count, data);
}
else {
LOG_ERROR("Unable to read sector count %i", int(sect_count));
@@ 247,7 257,7 @@ namespace purefs::fs::drivers
LOG_ERROR("LFS mount error %i", err);
}
if (!err) {
- filesystem_operations::mount(mnt);
+ filesystem_operations::mount(mnt, data);
}
else {
littlefs::internal::remove_volume(vmnt->lfs_config());
M module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp => module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp +2 -2
@@ 148,7 148,7 @@ namespace purefs::fs::drivers
return std::make_shared<mount_point_vfat>(diskh, path, flags, shared_from_this());
}
- auto filesystem_vfat::mount(fsmount mnt) noexcept -> int
+ auto filesystem_vfat::mount(fsmount mnt, const void *data) noexcept -> int
{
auto disk = mnt->disk();
if (!disk) {
@@ 168,7 168,7 @@ namespace purefs::fs::drivers
ret = f_mount(vmnt->fatfs(), vmnt->ff_drive(), 1);
ret = translate_error(ret);
if (!ret) {
- filesystem_operations::mount(mnt);
+ filesystem_operations::mount(mnt, data);
}
return ret;
}
R module-vfs/include/user/purefs/fs/filesystem_operations.hpp => module-vfs/include/internal/purefs/fs/filesystem_operations.hpp +4 -4
@@ 17,7 17,7 @@ namespace purefs::blkdev
class disk_handle;
}
class disk_manager;
-}
+} // namespace purefs::blkdev
namespace purefs::fs
{
@@ 44,9 44,9 @@ namespace purefs::fs
*/
virtual auto mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh,
std::string_view path,
- unsigned flags) -> fsmount = 0;
- virtual auto mount(fsmount mnt) noexcept -> int = 0;
- virtual auto umount(fsmount mnt) noexcept -> int = 0;
+ unsigned flags) -> fsmount = 0;
+ virtual auto mount(fsmount mnt, const void *data) noexcept -> int = 0;
+ virtual auto umount(fsmount mnt) noexcept -> int = 0;
virtual auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int;
/** Standard file access API */
M module-vfs/include/user/purefs/blkdev/partition.hpp => module-vfs/include/user/purefs/blkdev/partition.hpp +1 -0
@@ 16,6 16,7 @@ namespace purefs::blkdev
sector_t start_sector{}; //! First sector
std::size_t num_sectors{}; //! Number of sectors
bool bootable{}; //! Partition is bootable
+ unsigned char boot_unit{}; //! 7 bit boot unit field
unsigned short type{}; //! Partition code
std::string name; //! Partition name in block manager
};
M module-vfs/include/user/purefs/fs/filesystem.hpp => module-vfs/include/user/purefs/fs/filesystem.hpp +7 -2
@@ 80,13 80,18 @@ namespace purefs::fs
auto unregister_filesystem(std::string_view fsname) -> int;
/** Mount filesystem to the the specified mount point
+ * see man(2) mount
* @param[in] dev_or_part Device or partition for mount
* @param[in] target Target path where the fs will be mounted
* @param[in] flags Mount flags
+ * @param[in] data Filesystem specific configuration
* @return zero on success otherwise error
*/
- auto mount(std::string_view dev_or_part, std::string_view target, std::string_view fs_type, unsigned flags = 0)
- -> int;
+ auto mount(std::string_view dev_or_part,
+ std::string_view target,
+ std::string_view fs_type,
+ unsigned flags = 0,
+ const void *data = nullptr) -> int;
/** Unmont filesystem from selected mount point
* @param[in] mount_point Mount point where the fs is mounted
* @return zero on success otherwise error
M module-vfs/src/newlib/vfs_io_syscalls.cpp => module-vfs/src/newlib/vfs_io_syscalls.cpp +2 -2
@@ 353,9 353,9 @@ namespace vfsn::internal::syscalls
const char *dir,
const char *fstype,
unsigned long int rwflag,
- const void * /*data*/)
+ const void *data)
{
- return invoke_fs(_errno_, &purefs::fs::filesystem::mount, special_file, dir, fstype, rwflag);
+ return invoke_fs(_errno_, &purefs::fs::filesystem::mount, special_file, dir, fstype, rwflag, data);
}
} // namespace vfsn::internal::syscalls
M module-vfs/src/purefs/blkdev/partition_parser.cpp => module-vfs/src/purefs/blkdev/partition_parser.cpp +1 -0
@@ 94,6 94,7 @@ namespace purefs::blkdev::internal
std::size_t offs = defs::ptbl_offs;
for (auto &part : parts) {
part.bootable = buffer[defs::mbr_ptbl_active + offs] & 0x80;
+ part.boot_unit = buffer[defs::mbr_ptbl_active + offs] & 0x7F;
part.type = buffer[defs::mbr_ptbl_type + offs];
part.num_sectors = to_word(buffer, defs::mbr_ptbl_sect_cnt + offs);
part.start_sector = to_word(buffer, defs::mbr_ptbl_lba + offs);
M module-vfs/src/purefs/fs/filesystem.cpp => module-vfs/src/purefs/fs/filesystem.cpp +3 -2
@@ 69,7 69,8 @@ namespace purefs::fs
auto filesystem::mount(std::string_view dev_or_part,
std::string_view target,
std::string_view fs_type,
- unsigned flags) -> int
+ unsigned flags,
+ const void *data) -> int
{
// Sanity check input data
if (target.size() <= 1 || target[0] != '/') {
@@ 128,7 129,7 @@ namespace purefs::fs
}
if (diskh) {
const auto mnt_point = vsi->second->mount_prealloc(diskh, target, flags);
- const auto ret_mnt = vsi->second->mount(mnt_point);
+ const auto ret_mnt = vsi->second->mount(mnt_point, data);
if (!ret_mnt) {
m_mounts.emplace(std::make_pair(target, mnt_point));
m_partitions.emplace(dev_or_part);
M module-vfs/src/purefs/fs/filesystem_operations.cpp => module-vfs/src/purefs/fs/filesystem_operations.cpp +1 -1
@@ 8,7 8,7 @@
namespace purefs::fs
{
- auto filesystem_operations::mount(fsmount mnt) noexcept -> int
+ auto filesystem_operations::mount(fsmount mnt, const void *data) noexcept -> int
{
++m_mount_count;
return -ENOTSUP;
M module-vfs/src/purefs/vfs_subsystem.cpp => module-vfs/src/purefs/vfs_subsystem.cpp +14 -3
@@ 24,6 24,7 @@ namespace purefs::subsystem
constexpr auto old_layout_part_count = 2;
constexpr auto new_layout_part_count = 3;
constexpr auto boot_size_limit = 16384L;
+ constexpr auto block_size_max_shift = 21;
namespace json
{
constexpr auto os_type = "ostype";
@@ 150,8 151,9 @@ namespace purefs::subsystem
}
}
if (lfs_it == std::end(parts) && parts.size() == old_layout_part_count) {
- LOG_ERROR("!!!! Danger !!!! FAT partiton layout scheme. Data may be currupted when power loss.");
- LOG_WARN("Please upgrade to new partition scheme with LITTLEFS partition.");
+ LOG_ERROR("!!!! Caution !!!! eMMC is formated with vFAT old layout scheme. Filesystem may be currupted on "
+ "power loss.");
+ LOG_WARN("Please upgrade to new partition scheme based on the LittleFS filesystem.");
}
if (boot_it == std::end(parts)) {
LOG_FATAL("Unable to find boot partition");
@@ 167,7 169,16 @@ namespace purefs::subsystem
return err;
}
if (lfs_it != std::end(parts)) {
- err = vfs->mount(lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs");
+ if (lfs_it->boot_unit > block_size_max_shift) {
+ LOG_FATAL("Boot sector size is out of range");
+ return -ERANGE;
+ }
+ else {
+ const uint32_t lfs_block_size = 1U << lfs_it->boot_unit;
+ const auto lfs_block_size_ptr = (lfs_it->boot_unit) ? (&lfs_block_size) : nullptr;
+ err = vfs->mount(
+ lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs", 0, lfs_block_size_ptr);
+ }
}
const std::string json_file = (dir::getRootDiskPath() / file::boot_json).string();
const auto boot_dir_name = parse_boot_json_directory(json_file);