driver/block: add base class & ramdisk

This commit is contained in:
Edgaru089 2021-10-23 19:39:23 +08:00
parent a3fe5c5902
commit 71377dcc47
4 changed files with 217 additions and 0 deletions

View File

@ -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

View File

@ -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

72
driver/block/ramdisk.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "ramdisk.hpp"
#include "../../memory/memory.h"
#include "../../memory/paging_internal.h"
#include <cstring>
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

46
driver/block/ramdisk.hpp Normal file
View File

@ -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