summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-02-16 09:57:42 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-02-16 09:57:42 +0100
commit799177fedaee30b3e5ac655571633e9ea24964a5 (patch)
tree157e6ae6fb013fa84329f012d87d1da97a56a229
parent2dc7c5a7b09bc53d6b15362b61a19046b4611833 (diff)
downloadserenity-799177fedaee30b3e5ac655571633e9ea24964a5.zip
Kernel: Make BochsVGADevice a BlockDevice and support mmapping it.
Currently you can only mmap the entire framebuffer. Using this when starting up the WindowServer gets us yet another step closer towards it moving into userspace. :^)
-rw-r--r--Kernel/BlockDevice.h5
-rw-r--r--Kernel/BochsVGADevice.cpp38
-rw-r--r--Kernel/BochsVGADevice.h19
-rw-r--r--Kernel/CharacterDevice.h3
-rw-r--r--Kernel/Device.h3
-rw-r--r--Kernel/Ext2FileSystem.cpp7
-rw-r--r--Kernel/FileDescriptor.cpp48
-rw-r--r--Kernel/FileDescriptor.h16
-rw-r--r--Kernel/InodeMetadata.h1
-rw-r--r--Kernel/Process.cpp14
-rw-r--r--Kernel/Process.h6
-rw-r--r--Kernel/VirtualFileSystem.cpp2
-rw-r--r--Kernel/init.cpp2
-rwxr-xr-xKernel/sync.sh1
-rw-r--r--WindowServer/main.cpp16
15 files changed, 155 insertions, 26 deletions
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 <Kernel/BochsVGADevice.h>
#include <Kernel/IO.h>
#include <Kernel/PCI.h>
+#include <Kernel/MemoryManager.h>
+#include <Kernel/Process.h>
#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 <AK/Types.h>
#include <AK/AKString.h>
+#include <SharedGraphics/Size.h>
#include <Kernel/types.h>
+#include <Kernel/BlockDevice.h>
-// 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 <Kernel/Socket.h>
+#include <Kernel/Process.h>
+#include <Kernel/BlockDevice.h>
RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& 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<BlockDevice&>(*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<CharacterDevice*>(device()) : nullptr;
+}
+
+const CharacterDevice* FileDescriptor::character_device() const
+{
+ return is_character_device() ? static_cast<const CharacterDevice*>(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<FileDescriptor> {
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<Process>, public Weakable<Process> {
@@ -295,6 +294,9 @@ public:
int gui_client_id() const { return (int)this; }
+ Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr<VMObject>&&, size_t offset_in_vmo, String&& name, bool is_readable, bool is_writable);
+ Region* allocate_file_backed_region(LinearAddress, size_t, RetainPtr<Inode>&&, 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<Inode>&&, String&& name, bool is_readable, bool is_writable);
- Region* allocate_region_with_vmo(LinearAddress, size_t, RetainPtr<VMObject>&&, 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<FileDescriptor> 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(&params, 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(&params);
+ ASSERT(framebuffer && framebuffer != (void*)-1);
+
+ WSScreen screen((dword*)framebuffer, info.width, info.height);
WSWindowManager::the();