diff --git a/Kernel/BlockDevice.h b/Kernel/BlockDevice.h index 3f42270eb2..1a17a201fd 100644 --- a/Kernel/BlockDevice.h +++ b/Kernel/BlockDevice.h @@ -6,6 +6,11 @@ class BlockDevice : public Device { public: virtual ~BlockDevice() override; + virtual Region* mmap(Process&, LinearAddress preferred_laddr, size_t offset, size_t size) = 0; + protected: BlockDevice(unsigned major, unsigned minor) : Device(major, minor) { } + +private: + virtual bool is_block_device() const final { return true; } }; diff --git a/Kernel/BochsVGADevice.cpp b/Kernel/BochsVGADevice.cpp index ca3efec7f1..dd11e55fc7 100644 --- a/Kernel/BochsVGADevice.cpp +++ b/Kernel/BochsVGADevice.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #define VBE_DISPI_IOPORT_INDEX 0x01CE #define VBE_DISPI_IOPORT_DATA 0x01CF @@ -27,11 +29,25 @@ BochsVGADevice& BochsVGADevice::the() } BochsVGADevice::BochsVGADevice() + : BlockDevice(82, 413) { s_the = this; m_framebuffer_address = PhysicalAddress(find_framebuffer_address()); } +Region* BochsVGADevice::mmap(Process& process, LinearAddress preferred_laddr, size_t offset, size_t size) +{ + ASSERT(offset == 0); + ASSERT(size == framebuffer_size_in_bytes()); + auto framebuffer_vmo = VMObject::create_framebuffer_wrapper(framebuffer_address(), framebuffer_size_in_bytes()); + auto* region = process.allocate_region_with_vmo(preferred_laddr, framebuffer_size_in_bytes(), move(framebuffer_vmo), 0, "BochsVGADevice Framebuffer", true, true); + kprintf("BochsVGADevice::mmap for %s(%u) mapped region %p for fb addr %p\n", + process.name().characters(), process.pid(), + region, framebuffer_address()); + ASSERT(region); + return region; +} + void BochsVGADevice::set_register(word index, word data) { IO::out16(VBE_DISPI_IOPORT_INDEX, index); @@ -48,6 +64,8 @@ void BochsVGADevice::set_resolution(int width, int height) set_register(VBE_DISPI_INDEX_BPP, 32); set_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); set_register(VBE_DISPI_INDEX_BANK, 0); + + m_framebuffer_size = { width, height }; } void BochsVGADevice::set_y_offset(int offset) @@ -68,3 +86,23 @@ dword BochsVGADevice::find_framebuffer_address() }); return framebuffer_address; } + +bool BochsVGADevice::can_read(Process&) const +{ + ASSERT_NOT_REACHED(); +} + +bool BochsVGADevice::can_write(Process&) const +{ + ASSERT_NOT_REACHED(); +} + +ssize_t BochsVGADevice::read(Process&, byte*, size_t) +{ + ASSERT_NOT_REACHED(); +} + +ssize_t BochsVGADevice::write(Process&, const byte*, size_t) +{ + ASSERT_NOT_REACHED(); +} diff --git a/Kernel/BochsVGADevice.h b/Kernel/BochsVGADevice.h index 87cd9a1075..e1fa72bf8c 100644 --- a/Kernel/BochsVGADevice.h +++ b/Kernel/BochsVGADevice.h @@ -2,11 +2,11 @@ #include #include +#include #include +#include -// FIXME: This should be a BlockDevice once we have BlockDevice. - -class BochsVGADevice { +class BochsVGADevice final : public BlockDevice { AK_MAKE_ETERNAL public: static BochsVGADevice& the(); @@ -17,9 +17,22 @@ public: void set_resolution(int width, int height); void set_y_offset(int); + + virtual Region* mmap(Process&, LinearAddress preferred_laddr, size_t offset, size_t) override; + + size_t framebuffer_size_in_bytes() const { return m_framebuffer_size.area() * sizeof(dword) * 2; } + Size framebuffer_size() const { return m_framebuffer_size; } + private: + virtual const char* class_name() const override { return "BochsVGADevice"; } + virtual bool can_read(Process&) const override; + virtual bool can_write(Process&) const override; + virtual ssize_t read(Process&, byte*, size_t) override; + virtual ssize_t write(Process&, const byte*, size_t) override; + void set_register(word index, word value); dword find_framebuffer_address(); PhysicalAddress m_framebuffer_address; + Size m_framebuffer_size; }; diff --git a/Kernel/CharacterDevice.h b/Kernel/CharacterDevice.h index 387952482d..b81f1187fc 100644 --- a/Kernel/CharacterDevice.h +++ b/Kernel/CharacterDevice.h @@ -8,4 +8,7 @@ public: protected: CharacterDevice(unsigned major, unsigned minor) : Device(major, minor) { } + +private: + virtual bool is_character_device() const final { return true; } }; diff --git a/Kernel/Device.h b/Kernel/Device.h index a17af92259..52dbf10c13 100644 --- a/Kernel/Device.h +++ b/Kernel/Device.h @@ -35,6 +35,9 @@ public: uid_t uid() const { return m_uid; } uid_t gid() const { return m_gid; } + virtual bool is_block_device() const { return false; } + virtual bool is_character_device() const { return false; } + protected: Device(unsigned major, unsigned minor) : m_major(major), m_minor(minor) { } void set_uid(uid_t uid) { m_uid = uid; } diff --git a/Kernel/Ext2FileSystem.cpp b/Kernel/Ext2FileSystem.cpp index 34efa801f5..3f61afe72c 100644 --- a/Kernel/Ext2FileSystem.cpp +++ b/Kernel/Ext2FileSystem.cpp @@ -358,11 +358,16 @@ InodeMetadata Ext2FSInode::metadata() const metadata.block_size = fs().block_size(); metadata.block_count = m_raw_inode.i_blocks; - if (::is_block_device(m_raw_inode.i_mode) || ::is_character_device(m_raw_inode.i_mode)) { + if (::is_character_device(m_raw_inode.i_mode)) { unsigned dev = m_raw_inode.i_block[0]; metadata.major_device = (dev & 0xfff00) >> 8; metadata.minor_device = (dev & 0xff) | ((dev >> 12) & 0xfff00); } + if (::is_block_device(m_raw_inode.i_mode)) { + unsigned dev = m_raw_inode.i_block[1]; + metadata.major_device = (dev & 0xfff00) >> 8; + metadata.minor_device = (dev & 0xff) | ((dev >> 12) & 0xfff00); + } return metadata; } diff --git a/Kernel/FileDescriptor.cpp b/Kernel/FileDescriptor.cpp index d2bddc1bc5..5c171879eb 100644 --- a/Kernel/FileDescriptor.cpp +++ b/Kernel/FileDescriptor.cpp @@ -8,6 +8,8 @@ #include "TTY.h" #include "MasterPTY.h" #include +#include +#include RetainPtr FileDescriptor::create(RetainPtr&& inode) { @@ -338,3 +340,49 @@ InodeMetadata FileDescriptor::metadata() const return m_inode->metadata(); return { }; } + +bool FileDescriptor::supports_mmap() const +{ + if (m_inode) + return true; + if (m_device) + return m_device->is_block_device(); + return false; +} + +Region* FileDescriptor::mmap(Process& process, LinearAddress laddr, size_t offset, size_t size, int prot) +{ + ASSERT(supports_mmap()); + + if (is_block_device()) + return static_cast(*m_device).mmap(process, laddr, offset, size); + + ASSERT(m_inode); + // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. + auto region_name = absolute_path(); + InterruptDisabler disabler; + // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae. + ASSERT(laddr.as_ptr() == nullptr); + auto* region = process.allocate_file_backed_region(LinearAddress(), size, inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); + return region; +} + +bool FileDescriptor::is_block_device() const +{ + return m_device && m_device->is_block_device(); +} + +bool FileDescriptor::is_character_device() const +{ + return m_device && m_device->is_character_device(); +} + +CharacterDevice* FileDescriptor::character_device() +{ + return is_character_device() ? static_cast(device()) : nullptr; +} + +const CharacterDevice* FileDescriptor::character_device() const +{ + return is_character_device() ? static_cast(device()) : nullptr; +} diff --git a/Kernel/FileDescriptor.h b/Kernel/FileDescriptor.h index fef09b67ff..760f543199 100644 --- a/Kernel/FileDescriptor.h +++ b/Kernel/FileDescriptor.h @@ -12,6 +12,8 @@ class TTY; class MasterPTY; class Process; +class Region; +class CharacterDevice; class FileDescriptor : public Retainable { public: @@ -43,9 +45,14 @@ public: bool is_directory() const; - bool is_character_device() const { return m_device.ptr(); } - Device* character_device() { return m_device.ptr(); } - const Device* character_device() const { return m_device.ptr(); } + bool is_device() const { return m_device.ptr(); } + Device* device() { return m_device.ptr(); } + const Device* device() const { return m_device.ptr(); } + + bool is_block_device() const; + bool is_character_device() const; + CharacterDevice* character_device(); + const CharacterDevice* character_device() const; bool is_tty() const; const TTY* tty() const; @@ -59,7 +66,8 @@ public: Inode* inode() { return m_inode.ptr(); } const Inode* inode() const { return m_inode.ptr(); } - bool supports_mmap() const { return m_inode && !m_device; } + bool supports_mmap() const; + Region* mmap(Process&, LinearAddress, size_t offset, size_t, int prot); bool is_blocking() const { return m_is_blocking; } void set_blocking(bool b) { m_is_blocking = b; } diff --git a/Kernel/InodeMetadata.h b/Kernel/InodeMetadata.h index 8d6f08e942..8a5ffeb87b 100644 --- a/Kernel/InodeMetadata.h +++ b/Kernel/InodeMetadata.h @@ -30,6 +30,7 @@ struct InodeMetadata { bool is_directory() const { return ::is_directory(mode); } bool is_character_device() const { return ::is_character_device(mode); } bool is_block_device() const { return ::is_block_device(mode); } + bool is_device() const { return is_character_device() || is_block_device(); } bool is_regular_file() const { return ::is_regular_file(mode); } bool is_fifo() const { return ::is_fifo(mode); } bool is_symlink() const { return ::is_symlink(mode); } diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index b139fa93ba..51fb588dc3 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -182,12 +182,7 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params) return (void*)-EBADF; if (!descriptor->supports_mmap()) return (void*)-ENODEV; - // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. - auto region_name = descriptor->absolute_path(); - InterruptDisabler disabler; - // FIXME: Implement mapping at a client-specified address. Most of the support is already in plcae. - ASSERT(addr == nullptr); - auto* region = allocate_file_backed_region(LinearAddress(), size, descriptor->inode(), move(region_name), prot & PROT_READ, prot & PROT_WRITE); + auto* region = descriptor->mmap(*this, LinearAddress((dword)addr), offset, size, prot); if (!region) return (void*)-ENOMEM; return region->laddr().as_ptr(); @@ -2240,13 +2235,6 @@ DisplayInfo Process::set_video_resolution(int width, int height) info.height = height; info.bpp = 32; info.pitch = width * 4; - size_t framebuffer_size = width * height * 4 * 2; - if (!m_display_framebuffer_region) { - auto framebuffer_vmo = VMObject::create_framebuffer_wrapper(BochsVGADevice::the().framebuffer_address(), framebuffer_size); - m_display_framebuffer_region = allocate_region_with_vmo(LinearAddress(0xe0000000), framebuffer_size, move(framebuffer_vmo), 0, "framebuffer", true, true); - } - info.framebuffer = m_display_framebuffer_region->laddr().as_ptr(); - BochsVGADevice::the().set_resolution(width, height); return info; } diff --git a/Kernel/Process.h b/Kernel/Process.h index 66c7528966..e75b2279ee 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -44,7 +44,6 @@ struct DisplayInfo { unsigned height; unsigned bpp; unsigned pitch; - byte* framebuffer; }; class Process : public InlineLinkedListNode, public Weakable { @@ -295,6 +294,9 @@ public: int gui_client_id() const { return (int)this; } + Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable); + Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr&&, String&& name, bool is_readable, bool is_writable); + private: friend class MemoryManager; friend class Scheduler; @@ -366,8 +368,6 @@ private: TTY* m_tty { nullptr }; Region* allocate_region(LinearAddress, size_t, String&& name, bool is_readable = true, bool is_writable = true, bool commit = true); - Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr&&, String&& name, bool is_readable, bool is_writable); - Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable); bool deallocate_region(Region& region); Region* region_from_range(LinearAddress, size_t); diff --git a/Kernel/VirtualFileSystem.cpp b/Kernel/VirtualFileSystem.cpp index 9254b4342a..55f2c41c9d 100644 --- a/Kernel/VirtualFileSystem.cpp +++ b/Kernel/VirtualFileSystem.cpp @@ -145,7 +145,7 @@ RetainPtr VFS::open(const String& path, int& error, int options, if (!inode) return nullptr; auto metadata = inode->metadata(); - if (!(options & O_DONT_OPEN_DEVICE) && metadata.is_character_device()) { + if (!(options & O_DONT_OPEN_DEVICE) && metadata.is_device()) { auto it = m_devices.find(encoded_device(metadata.major_device, metadata.minor_device)); if (it == m_devices.end()) { kprintf("VFS::open: no such device %u,%u\n", metadata.major_device, metadata.minor_device); diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 936985de87..c26c372adc 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -86,6 +86,8 @@ VFS* vfs; vfs->register_device(*tty2); vfs->register_device(*tty3); + vfs->register_device(BochsVGADevice::the()); + auto dev_hd0 = IDEDiskDevice::create(); auto e2fs = Ext2FS::create(dev_hd0.copy_ref()); e2fs->initialize(); diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 7499a71413..d73c1770c3 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -16,6 +16,7 @@ mkdir -vp mnt/tmp chmod 1777 mnt/tmp mkdir -vp mnt/dev mkdir -vp mnt/dev/pts +mknod mnt/dev/bxvga b 82 413 mknod mnt/dev/tty0 c 4 0 mknod mnt/dev/tty1 c 4 1 mknod mnt/dev/tty2 c 4 2 diff --git a/WindowServer/main.cpp b/WindowServer/main.cpp index c551eeed63..89ea79a5e2 100644 --- a/WindowServer/main.cpp +++ b/WindowServer/main.cpp @@ -16,7 +16,21 @@ void WindowServer_main() dbgprintf("Screen is %ux%ux%ubpp\n", info.width, info.height, info.bpp); - WSScreen screen((dword*)info.framebuffer, info.width, info.height); + int bxvga_fd = current->sys$open("/dev/bxvga", O_RDWR); + ASSERT(bxvga_fd >= 0); + + Syscall::SC_mmap_params params; + memset(¶ms, 0, sizeof(params)); + params.fd = bxvga_fd; + params.prot = PROT_READ | PROT_WRITE; + params.flags = MAP_SHARED; + params.size = info.width * info.height * sizeof(RGBA32) * 2; + params.offset = 0; + kprintf("Calling sys$mmap in WS\n"); + void* framebuffer = current->sys$mmap(¶ms); + ASSERT(framebuffer && framebuffer != (void*)-1); + + WSScreen screen((dword*)framebuffer, info.width, info.height); WSWindowManager::the();