diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/devices/include/devices/block_device.hpp | 22 | ||||
| -rw-r--r-- | kernel/devices/include/devices/device.hpp | 9 | ||||
| -rw-r--r-- | kernel/devices/src/block_device.cpp | 19 | ||||
| -rw-r--r-- | kernel/filesystem/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | kernel/filesystem/include/filesystem/device_file.hpp | 30 | ||||
| -rw-r--r-- | kernel/filesystem/include/filesystem/open_file_description.hpp | 2 | ||||
| -rw-r--r-- | kernel/filesystem/src/device_file.cpp | 119 | ||||
| -rw-r--r-- | kernel/filesystem/src/open_file_description.cpp | 4 |
8 files changed, 209 insertions, 2 deletions
diff --git a/kernel/devices/include/devices/block_device.hpp b/kernel/devices/include/devices/block_device.hpp index 78a2606..9bca53f 100644 --- a/kernel/devices/include/devices/block_device.hpp +++ b/kernel/devices/include/devices/block_device.hpp @@ -46,6 +46,28 @@ namespace devices */ virtual auto write_block(size_t block_index, void const * buffer) -> void = 0; + /** + * @brief Return logical block size in bytes. + * @return One logical block size in bytes. + */ + auto block_size() const -> size_t; + + /** + * @brief Return device capacity in bytes. + * @return Total number of addressable bytes. + */ + auto capacity() const -> size_t; + + /** + * @brief Override to identify block devices. + * @return true if this device is a block device, false otherwise. + */ + + auto is_block_device() const -> bool override + { + return true; + } + protected: /** * @brief Information describing the transfer window for one block index. diff --git a/kernel/devices/include/devices/device.hpp b/kernel/devices/include/devices/device.hpp index cbf77c2..7f9f9e1 100644 --- a/kernel/devices/include/devices/device.hpp +++ b/kernel/devices/include/devices/device.hpp @@ -34,6 +34,15 @@ namespace devices */ auto minor() const -> size_t; + /** + * @brief Check if the device is a block device. + * @return true if this device is a block device, false otherwise. + */ + virtual auto is_block_device() const -> bool + { + return false; + } + private: size_t m_major; size_t m_minor; diff --git a/kernel/devices/src/block_device.cpp b/kernel/devices/src/block_device.cpp index dd63638..2f0c2ca 100644 --- a/kernel/devices/src/block_device.cpp +++ b/kernel/devices/src/block_device.cpp @@ -1,5 +1,7 @@ #include "devices/block_device.hpp" +#include "kapi/system.hpp" + #include "devices/device.hpp" #include <cstddef> @@ -9,7 +11,12 @@ namespace devices block_device::block_device(size_t major, size_t minor, size_t block_size) : device(major, minor) , m_block_size(block_size) - {} + { + if (m_block_size == 0) + { + kapi::system::panic("[DEVICES] block_device constructed with zero block size."); + } + } auto block_device::calculate_transfer(size_t block_index) const -> transfer_info { @@ -21,4 +28,14 @@ namespace devices return {offset, to_transfer, m_block_size - to_transfer}; } + + auto block_device::block_size() const -> size_t + { + return m_block_size; + } + + auto block_device::capacity() const -> size_t + { + return size(); + } } // namespace devices
\ No newline at end of file diff --git a/kernel/filesystem/CMakeLists.txt b/kernel/filesystem/CMakeLists.txt index 2a93c62..1d74585 100644 --- a/kernel/filesystem/CMakeLists.txt +++ b/kernel/filesystem/CMakeLists.txt @@ -3,6 +3,7 @@ add_library("kernel::filesystem" ALIAS "kernel_filesystem") target_sources("kernel_filesystem" PRIVATE "src/file.cpp" + "src/device_file.cpp" "src/open_file_description.cpp" "src/file_descriptor_table.cpp" ) @@ -12,6 +13,7 @@ target_sources("kernel_filesystem" PUBLIC BASE_DIRS "include" FILES "include/filesystem/file.hpp" + "include/filesystem/device_file.hpp" "include/filesystem/open_file_description.hpp" "include/filesystem/file_descriptor_table.hpp" ) @@ -20,6 +22,8 @@ target_include_directories("kernel_filesystem" PUBLIC "include" ) -target_link_libraries("kernel_filesystem" PRIVATE +target_link_libraries("kernel_filesystem" PUBLIC + "kernel::devices" +PRIVATE "os::kapi" ) diff --git a/kernel/filesystem/include/filesystem/device_file.hpp b/kernel/filesystem/include/filesystem/device_file.hpp new file mode 100644 index 0000000..08d81f6 --- /dev/null +++ b/kernel/filesystem/include/filesystem/device_file.hpp @@ -0,0 +1,30 @@ +#ifndef TEACH_OS_KERNEL_FILESYSTEM_DEVICE_FILE_HPP +#define TEACH_OS_KERNEL_FILESYSTEM_DEVICE_FILE_HPP + +#include "devices/block_device.hpp" +#include "devices/device.hpp" +#include "filesystem/file.hpp" + +#include <cstddef> + +namespace filesystem +{ + struct device_file : file + { + device_file(devices::device * device); + + auto open() -> void override; + + auto read(void * buffer, size_t offset, size_t size) const -> size_t override; + auto write(void const * buffer, size_t offset, size_t size) -> size_t override; + + private: + using block_op = void (*)(size_t idx, size_t off, size_t len, size_t done, devices::block_device * device, + std::byte * scratch, void * buffer); + auto process_blocks(size_t offset, size_t size, void * buffer, block_op op) const -> size_t; + + devices::device * m_device; + }; +} // namespace filesystem + +#endif diff --git a/kernel/filesystem/include/filesystem/open_file_description.hpp b/kernel/filesystem/include/filesystem/open_file_description.hpp index e4febbd..3241ea4 100644 --- a/kernel/filesystem/include/filesystem/open_file_description.hpp +++ b/kernel/filesystem/include/filesystem/open_file_description.hpp @@ -9,6 +9,8 @@ namespace filesystem { struct open_file_description { + open_file_description(file * file); + ~open_file_description() = default; auto read(void * buffer, size_t size) -> size_t; diff --git a/kernel/filesystem/src/device_file.cpp b/kernel/filesystem/src/device_file.cpp new file mode 100644 index 0000000..a6c234c --- /dev/null +++ b/kernel/filesystem/src/device_file.cpp @@ -0,0 +1,119 @@ +#include "filesystem/device_file.hpp" + +#include "kapi/system.hpp" + +#include "devices/block_device.hpp" +#include "devices/device.hpp" + +#include <kstd/cstring> + +#include <algorithm> +#include <array> +#include <cstddef> + +namespace filesystem +{ + device_file::device_file(devices::device * device) + : m_device(device) + { + if (m_device == nullptr) + { + kapi::system::panic("[FILESYSTEM] device_file constructed with null device."); + } + } + + auto device_file::open() -> void + { + // Hook point for permission checks or lazy metadata loading. + } + + auto device_file::read(void * buffer, size_t offset, size_t size) const -> size_t + { + if (m_device->is_block_device()) + { + return process_blocks(offset, size, buffer, + [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device, + std::byte * scratch, void * buffer) { + auto * out = static_cast<std::byte *>(buffer); + if (off == 0 && len == device->block_size()) + { + device->read_block(idx, out + done); + } + else + { + device->read_block(idx, scratch); + kstd::libc::memcpy(out + done, scratch + off, len); + } + }); + } + else + { + kapi::system::panic("[FILESYSTEM] device_file::read called on non-block device."); + } + } + + auto device_file::write(void const * buffer, size_t offset, size_t size) -> size_t + { + if (m_device->is_block_device()) + { + return process_blocks(offset, size, const_cast<void *>(buffer), + [](size_t idx, size_t off, size_t len, size_t done, devices::block_device * device, + std::byte * scratch, void * buffer) { + auto const * in = static_cast<std::byte const *>(buffer); + if (off == 0 && len == device->block_size()) + { + device->write_block(idx, in + done); + } + else + { + device->read_block(idx, scratch); + kstd::libc::memcpy(scratch + off, in + done, len); + device->write_block(idx, scratch); + } + }); + } + else + { + kapi::system::panic("[FILESYSTEM] device_file::write called on non-block device."); + } + } + + auto device_file::process_blocks(size_t offset, size_t size, void * buffer, block_op op) const -> size_t + { + if (buffer == nullptr) + { + kapi::system::panic("[FILESYSTEM] device_file::write called with null buffer."); + } + + if (size == 0) + { + return 0; + } + + auto * block_dev = static_cast<devices::block_device *>(m_device); + + size_t const block_size = block_dev->block_size(); + size_t const capacity = block_dev->capacity(); + + if (offset >= capacity) + return 0; + size_t const total_to_process = std::min(size, capacity - offset); + + std::array<std::byte, 512> scratch_buffer{}; // TODO BA-FS26 better solution than fixed scratch_buffer ?? + auto processed = 0uz; + + while (processed < total_to_process) + { + size_t const absolute_offset = offset + processed; + size_t const block_index = absolute_offset / block_size; + size_t const in_block_offset = absolute_offset % block_size; + size_t const chunk_size = std::min(total_to_process - processed, block_size - in_block_offset); + + op(block_index, in_block_offset, chunk_size, processed, block_dev, scratch_buffer.data(), buffer); + + processed += chunk_size; + } + + return processed; + } +} // namespace filesystem diff --git a/kernel/filesystem/src/open_file_description.cpp b/kernel/filesystem/src/open_file_description.cpp index 8c20397..1f0410c 100644 --- a/kernel/filesystem/src/open_file_description.cpp +++ b/kernel/filesystem/src/open_file_description.cpp @@ -6,6 +6,10 @@ namespace filesystem { + open_file_description::open_file_description(file * file) + : m_file(file) + {} + auto open_file_description::read(void * buffer, size_t size) -> size_t { // TODO BA-FS26 nullptr check |
