driver/block: add base class & ramdisk
This commit is contained in:
parent
a3fe5c5902
commit
71377dcc47
48
driver/block/blockdevice.cpp
Normal file
48
driver/block/blockdevice.cpp
Normal 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
|
51
driver/block/blockdevice.hpp
Normal file
51
driver/block/blockdevice.hpp
Normal 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
72
driver/block/ramdisk.cpp
Normal 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
46
driver/block/ramdisk.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user