소스 검색

Add basic character device support. Start with null and zero.

Andreas Kling 6 년 전
부모
커밋
93556d6743

+ 7 - 0
VirtualFileSystem/CharacterDevice.cpp

@@ -0,0 +1,7 @@
+#include "CharacterDevice.h"
+
+CharacterDevice::~CharacterDevice()
+{
+}
+
+

+ 15 - 0
VirtualFileSystem/CharacterDevice.h

@@ -0,0 +1,15 @@
+#pragma once
+
+#include <AK/Types.h>
+#include "Limits.h"
+
+class CharacterDevice {
+public:
+    virtual ~CharacterDevice();
+
+    virtual ssize_t read(byte* buffer, size_t bufferSize) = 0;
+    virtual ssize_t write(const byte* buffer, size_t bufferSize) = 0;
+
+protected:
+    CharacterDevice() { }
+};

+ 9 - 1
VirtualFileSystem/FileHandle.cpp

@@ -1,5 +1,6 @@
 #include "FileHandle.h"
 #include "FileSystem.h"
+#include "CharacterDevice.h"
 
 FileHandle::FileHandle(RetainPtr<VirtualFileSystem::Node>&& vnode)
     : m_vnode(std::move(vnode))
@@ -10,8 +11,15 @@ FileHandle::~FileHandle()
 {
 }
 
-ByteBuffer FileHandle::read() const
+ByteBuffer FileHandle::read()
 {
+    if (m_vnode->isCharacterDevice()) {
+        auto buffer = ByteBuffer::createUninitialized(1024);
+        ssize_t nread = m_vnode->characterDevice()->read(buffer.pointer(), buffer.size());
+        buffer.trim(nread);
+        return buffer;
+    }
+
     return m_vnode->fileSystem()->readInode(m_vnode->inode);
 }
 

+ 1 - 1
VirtualFileSystem/FileHandle.h

@@ -8,7 +8,7 @@ public:
     explicit FileHandle(RetainPtr<VirtualFileSystem::Node>&&);
     ~FileHandle();
 
-    ByteBuffer read() const;
+    ByteBuffer read();
 
 private:
     friend class VirtualFileSystem;

+ 6 - 0
VirtualFileSystem/Limits.h

@@ -0,0 +1,6 @@
+#pragma once
+
+typedef dword size_t;
+typedef signed_dword ssize_t;
+
+static const size_t GoodBufferSize = 4096;

+ 1 - 0
VirtualFileSystem/Makefile

@@ -20,6 +20,7 @@ VFS_OBJS = \
     InodeIdentifier.o \
     CharacterDevice.o \
     ZeroDevice.o \
+    NullDevice.o \
     test.o
 
 OBJS = $(AK_OBJS) $(VFS_OBJS)

+ 25 - 0
VirtualFileSystem/NullDevice.cpp

@@ -0,0 +1,25 @@
+#include "NullDevice.h"
+#include "Limits.h"
+#include <AK/StdLib.h>
+#include <cstring>
+#include <cstdio>
+
+NullDevice::NullDevice()
+{
+}
+
+NullDevice::~NullDevice()
+{
+}
+
+ssize_t NullDevice::read(byte*, size_t)
+{
+    printf("read from null\n");
+    return 0;
+}
+
+ssize_t NullDevice::write(const byte*, size_t bufferSize)
+{
+    return min(GoodBufferSize, bufferSize);
+}
+

+ 13 - 0
VirtualFileSystem/NullDevice.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "CharacterDevice.h"
+
+class NullDevice final : public CharacterDevice {
+public:
+    NullDevice();
+    virtual ~NullDevice();
+
+    ssize_t read(byte* buffer, size_t bufferSize) override;
+    ssize_t write(const byte* buffer, size_t bufferSize) override;
+};
+

+ 22 - 0
VirtualFileSystem/VirtualFileSystem.cpp

@@ -7,6 +7,11 @@
 
 //#define VFS_DEBUG
 
+static dword encodedDevice(unsigned major, unsigned minor)
+{
+    return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
+}
+
 VirtualFileSystem::VirtualFileSystem()
 {
     m_maxNodeCount = 16;
@@ -28,6 +33,17 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
     if (!metadata.isValid())
         return nullptr;
 
+    CharacterDevice* characterDevice = nullptr;
+    if (metadata.isCharacterDevice()) {
+        auto it = m_characterDevices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice));
+        if (it != m_characterDevices.end()) {
+            characterDevice = (*it).value;
+        } else {
+            printf("[VFS] makeNode() no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice);
+            return nullptr;
+        }
+    }
+
     auto vnode = allocateNode();
     ASSERT(vnode);
 
@@ -41,6 +57,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
 #endif
 
     m_inode2vnode.set(inode, vnode.ptr());
+    vnode->m_characterDevice = characterDevice;
     return vnode;
 }
 
@@ -118,6 +135,7 @@ void VirtualFileSystem::freeNode(Node* node)
     m_inode2vnode.remove(node->inode);
     node->inode.fileSystem()->release();
     node->inode = InodeIdentifier();
+    node->m_characterDevice = nullptr;
     m_nodeFreeList.append(std::move(node));
 }
 
@@ -415,3 +433,7 @@ VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr<FileSystem>&& gu
 {
 }
 
+void VirtualFileSystem::registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice& device)
+{
+    m_characterDevices.set(encodedDevice(major, minor), &device);
+}

+ 10 - 0
VirtualFileSystem/VirtualFileSystem.h

@@ -7,6 +7,7 @@
 #include <AK/Vector.h>
 #include "InodeIdentifier.h"
 
+class CharacterDevice;
 class FileHandle;
 class FileSystem;
 
@@ -17,6 +18,9 @@ public:
 
         bool inUse() const { return inode.isValid(); }
 
+        bool isCharacterDevice() const { return m_characterDevice; }
+        CharacterDevice* characterDevice() { return m_characterDevice; }
+
         void retain();
         void release();
 
@@ -27,6 +31,7 @@ public:
         friend class VirtualFileSystem;
         VirtualFileSystem* vfs { nullptr };
         unsigned retainCount { 0 };
+        CharacterDevice* m_characterDevice { nullptr };
     };
 
     VirtualFileSystem();
@@ -52,6 +57,8 @@ public:
 
     bool touch(const String&path);
 
+    void registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice&);
+
 private:
     template<typename F> void enumerateDirectoryInode(InodeIdentifier, F func);
     InodeIdentifier resolvePath(const String& path);
@@ -80,6 +87,7 @@ private:
     Mount* findMountForGuest(InodeIdentifier);
 
     HashMap<InodeIdentifier, Node*> m_inode2vnode;
+    HashMap<dword, Node*> m_device2vnode;
 
     Vector<OwnPtr<Mount>> m_mounts;
 
@@ -89,5 +97,7 @@ private:
     Vector<Node*> m_nodeFreeList;
 
     RetainPtr<Node> m_rootNode;
+
+    HashMap<dword, CharacterDevice*> m_characterDevices;
 };
 

+ 27 - 0
VirtualFileSystem/ZeroDevice.cpp

@@ -0,0 +1,27 @@
+#include "ZeroDevice.h"
+#include "Limits.h"
+#include <AK/StdLib.h>
+#include <cstring>
+#include <cstdio>
+
+ZeroDevice::ZeroDevice()
+{
+}
+
+ZeroDevice::~ZeroDevice()
+{
+}
+
+ssize_t ZeroDevice::read(byte* buffer, size_t bufferSize)
+{
+    printf("read from zero device\n");
+    size_t count = min(GoodBufferSize, bufferSize);
+    memset(buffer, 0, count);
+    return count;
+}
+
+ssize_t ZeroDevice::write(const byte*, size_t bufferSize)
+{
+    return min(GoodBufferSize, bufferSize);
+}
+

+ 13 - 0
VirtualFileSystem/ZeroDevice.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "CharacterDevice.h"
+
+class ZeroDevice final : public CharacterDevice {
+public:
+    ZeroDevice();
+    virtual ~ZeroDevice();
+
+    ssize_t read(byte* buffer, size_t bufferSize) override;
+    ssize_t write(const byte* buffer, size_t bufferSize) override;
+};
+

BIN
VirtualFileSystem/small.fs


+ 8 - 0
VirtualFileSystem/test.cpp

@@ -3,6 +3,8 @@
 #include "VirtualFileSystem.h"
 #include "FileHandle.h"
 #include "SyntheticFileSystem.h"
+#include "ZeroDevice.h"
+#include "NullDevice.h"
 #include <cstring>
 #include <AK/SimpleMalloc.h>
 #include <AK/kmalloc.h>
@@ -17,6 +19,12 @@ int main(int c, char** v)
 
     VirtualFileSystem vfs;
 
+    auto zero = make<ZeroDevice>();
+    vfs.registerCharacterDevice(1, 5, *zero);
+
+    auto null = make<NullDevice>();
+    vfs.registerCharacterDevice(1, 3, *null);
+
     if (!vfs.mountRoot(makeFileSystem(filename))) {
         printf("Failed to mount root :(\n");
         return 1;