From 71377dcc47847d176b543ff5651f2cc20f58e13a Mon Sep 17 00:00:00 2001 From: Edgaru089 Date: Sat, 23 Oct 2021 19:39:23 +0800 Subject: [PATCH] driver/block: add base class & ramdisk --- driver/block/blockdevice.cpp | 48 ++++++++++++++++++++++++ driver/block/blockdevice.hpp | 51 +++++++++++++++++++++++++ driver/block/ramdisk.cpp | 72 ++++++++++++++++++++++++++++++++++++ driver/block/ramdisk.hpp | 46 +++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 driver/block/blockdevice.cpp create mode 100644 driver/block/blockdevice.hpp create mode 100644 driver/block/ramdisk.cpp create mode 100644 driver/block/ramdisk.hpp diff --git a/driver/block/blockdevice.cpp b/driver/block/blockdevice.cpp new file mode 100644 index 0000000..965f89a --- /dev/null +++ b/driver/block/blockdevice.cpp @@ -0,0 +1,48 @@ + +#include "blockdevice.hpp" + +namespace helos { + + +class SlicedBlockDevice: public BlockDevice { +public: + SlicedBlockDevice(BlockDevice *backing, uint64_t off, uint64_t cnt) + : backing(backing), off(off), cnt(cnt) {} + +public: + virtual uint64_t BlockSize() const override { + return backing->BlockSize(); + } + + uint64_t Size() const override { + return cnt; + } + + uint64_t SizeBytes() const override { + return backing->BlockSize() * cnt; + } + + ::helos::Permission Permission() const override { + return backing->Permission(); + } + + uint64_t ReadBlock(uint64_t blockOffset, void *data, uint64_t blockCount) const override { + return backing->ReadBlock(blockOffset + off, data, blockCount); + } + + uint64_t WriteBlock(uint64_t blockOffset, const void *data, uint64_t blockCount) override { + return backing->WriteBlock(blockOffset + off, data, blockCount); + } + +private: + BlockDevice *backing; + uint64_t off, cnt; +}; + + +BlockDevice *BlockDevice::Slice(uint64_t blockOffset, uint64_t blockCount) { + return new SlicedBlockDevice(this, blockOffset, blockCount); +} + + +} // namespace helos diff --git a/driver/block/blockdevice.hpp b/driver/block/blockdevice.hpp new file mode 100644 index 0000000..bdf20cc --- /dev/null +++ b/driver/block/blockdevice.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "../../main.h" +#include "../../cppruntime/runtime.hpp" + +namespace helos { + + +// BlockDevice describes random-access storage devices organizing data in blocks of uniform sizes. +class BlockDevice { +public: + virtual ~BlockDevice() {} + + // BlockSize returns the size, in bytes, of the data block. + // It is to remain constant throughout the lifetime of the device. + virtual uint64_t BlockSize() const = 0; + + // Size returns the size, in blocks, of the entire device. + virtual uint64_t Size() const = 0; + + // SizeBytes returns the size of the entire device in bytes. + virtual uint64_t SizeBytes() const { + return BlockSize() * Size(); + } + + + // Permission returns the permission on the entire device (Read, Write, Exec) + virtual Permission Permission() const { + return PermRead | PermWrite | PermExecute; + } + + // ReadBlock reads, from the block device, blockCount blocks of data into the buffer. + // + // Returns the number of blocks read, or a negative number on error. + virtual uint64_t ReadBlock(uint64_t blockOffset, void *data, uint64_t blockCount) const = 0; + + // WriteBlock writes into the block device blockCount blocks. + // + // Returns the number of blocks written, or a negative number on error. + // (no data is written on error) + virtual uint64_t WriteBlock(uint64_t blockOffset, const void *data, uint64_t blockCount) = 0; + + +public: + // Slice creates a new BlockDevice reading from a portion of the underlying device. + // The underlying device must be kept alive as long as the slice exists. + BlockDevice *Slice(uint64_t blockOffset, uint64_t blockCount); +}; + + +} // namespace helos diff --git a/driver/block/ramdisk.cpp b/driver/block/ramdisk.cpp new file mode 100644 index 0000000..133799d --- /dev/null +++ b/driver/block/ramdisk.cpp @@ -0,0 +1,72 @@ + +#include "ramdisk.hpp" +#include "../../memory/memory.h" +#include "../../memory/paging_internal.h" +#include + +namespace helos { + + +constexpr uint16_t __Ramdisk_Alloc_None = 0, + __Ramdisk_Alloc_Malloc = 1, + __Ramdisk_Alloc_4KPages = 2, + __Ramdisk_Alloc_2MPages = 3; + +BlockDeviceRamdisk::BlockDeviceRamdisk(uint64_t blockSize, uint64_t blockCount, ::helos::Permission perm) + : blocksize(blockSize), blockcount(blockCount), perm(perm) { + uint64_t bytes = blockSize * blockCount; // the number of bytes to allocate + + if (bytes < SYSTEM_PAGE_SIZE) { + // less than a page: use malloc() + alloctype = __Ramdisk_Alloc_Malloc; + buffer = kMalloc(bytes); + } else if (bytes < SYSTEM_PAGE_2M_SIZE * 64) { + // less than 128M: 4K pages + alloctype = __Ramdisk_Alloc_4KPages; + buffer = (void *)memory_AllocateKernelMapping(bytes, SYSTEM_PAGE_SIZE); + paging_map_PageAllocated((uint64_t)buffer, pages = roundUpToPageCount(bytes), (int)perm); + } else { + // more than 128M: 2M pages + alloctype = __Ramdisk_Alloc_2MPages; + buffer = (void *)memory_AllocateKernelMapping(bytes, SYSTEM_PAGE_2M_SIZE); + paging_map_PageAllocated2M((uint64_t)buffer, pages = roundUpToPageCount2M(bytes), (int)perm); + } +} + +BlockDeviceRamdisk::BlockDeviceRamdisk(void *buffer, uint64_t blockSize, uint64_t blockCount, ::helos ::Permission perm) + : buffer(buffer), blocksize(blockSize), blockcount(blockCount), perm(perm), alloctype(__Ramdisk_Alloc_None) {} + +BlockDeviceRamdisk::~BlockDeviceRamdisk() { + switch (alloctype) { + case __Ramdisk_Alloc_Malloc: + kFree(buffer); + break; + case __Ramdisk_Alloc_4KPages: + case __Ramdisk_Alloc_2MPages: + paging_map_FreeAllocated( + (uint64_t)buffer, + (uint64_t)buffer + pages * ((alloctype == __Ramdisk_Alloc_4KPages) ? SYSTEM_PAGE_SIZE : SYSTEM_PAGE_2M_SIZE)); + break; + } +} + +uint64_t BlockDeviceRamdisk::ReadBlock(uint64_t offset, void *data, uint64_t count) const { + if (!(perm & PermRead)) + return -1; + if (count > blockcount - offset) + count = blockcount - offset; + memcpy(data, (uint8_t *)buffer + blocksize * offset, blocksize * count); + return count; +} + +uint64_t BlockDeviceRamdisk::WriteBlock(uint64_t offset, const void *data, uint64_t count) { + if (!(perm & PermRead)) + return -1; + if (count > blockcount - offset) + count = blockcount - offset; + memcpy((uint8_t *)buffer + blocksize * offset, data, blocksize * count); + return count; +} + + +} // namespace helos diff --git a/driver/block/ramdisk.hpp b/driver/block/ramdisk.hpp new file mode 100644 index 0000000..0407dd7 --- /dev/null +++ b/driver/block/ramdisk.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "blockdevice.hpp" + +namespace helos { + + +// Ramdisk is a block device residing in runtime RAM. +class BlockDeviceRamdisk: public BlockDevice { +public: + BlockDeviceRamdisk(const BlockDeviceRamdisk &) = delete; // Don't copy by value + BlockDeviceRamdisk(BlockDeviceRamdisk &&) = delete; + const BlockDeviceRamdisk &operator=(const BlockDeviceRamdisk &) = delete; + +public: + // Creates new, empty (all zero) ramdisk, allocating from kernel memory + BlockDeviceRamdisk(uint64_t blockSize, uint64_t blockCount, ::helos::Permission perm); + // Creates a Ramdisk wrapper from an existing buffer + // Size of the buffer must be a multiple of BlockSize + BlockDeviceRamdisk(void *buffer, uint64_t blockSize, uint64_t blockCount, ::helos ::Permission perm); + ~BlockDeviceRamdisk(); + +public: + uint64_t BlockSize() const override { return blocksize; } + uint64_t Size() const override { return blockcount; } + uint64_t SizeBytes() const override { return blocksize * blockcount; } + + ::helos::Permission Permission() const override { return perm; } + + uint64_t ReadBlock(uint64_t blockOffset, void *data, uint64_t blockCount) const override; + uint64_t WriteBlock(uint64_t blockOffset, const void *data, uint64_t blockCount) override; + +public: + // Buffer returns the underlying buffer. + void *Buffer() { return buffer; } + +private: + uint64_t blocksize, blockcount; + void * buffer; + int pages; // Number of pages allocated in 4K or 2M paging allocation + ::helos::Permission perm; + uint16_t alloctype; // Type of the buffer allocated +}; + + +} // namespace helos