driver/block: add base class & ramdisk
This commit is contained in:
		
							
								
								
									
										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 | ||||
		Reference in New Issue
	
	Block a user