mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
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. :^)
This commit is contained in:
parent
2dc7c5a7b0
commit
799177feda
Notes:
sideshowbarker
2024-07-19 15:42:11 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/799177fedae
15 changed files with 155 additions and 26 deletions
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -8,4 +8,7 @@ public:
|
|||
|
||||
protected:
|
||||
CharacterDevice(unsigned major, unsigned minor) : Device(major, minor) { }
|
||||
|
||||
private:
|
||||
virtual bool is_character_device() const final { return true; }
|
||||
};
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue