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