1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 19:28:12 +00:00

Add mechanism to expose kernel variables to userspace via ProcFS.

Only booleans are supported at first. More types can be added easily.
Use this to add /proc/sys/wm_flash_flush which when enabled flashes pending
screen flush rects in yellow before they happen.
This commit is contained in:
Andreas Kling 2019-01-18 15:01:40 +01:00
parent 9454c5dd52
commit f7cc454162
8 changed files with 121 additions and 29 deletions

View file

@ -15,6 +15,7 @@
class Process;
extern Process* current;
class SynthFSInode;
enum class PageFaultResponse {
ShouldCrash,
@ -166,7 +167,7 @@ class MemoryManager {
friend class PhysicalPage;
friend class Region;
friend class VMObject;
friend ByteBuffer procfs$mm();
friend ByteBuffer procfs$mm(SynthFSInode&);
public:
static MemoryManager& the() PURE;

View file

@ -156,15 +156,15 @@ void ProcFS::add_process(Process& process)
ksprintf(buf, "%d", process.pid());
auto dir = add_file(create_directory(buf));
m_pid2inode.set(process.pid(), dir.index());
add_file(create_generated_file("vm", [&process] { return procfs$pid_vm(process); }), dir.index());
add_file(create_generated_file("vmo", [&process] { return procfs$pid_vmo(process); }), dir.index());
add_file(create_generated_file("stack", [&process] { return procfs$pid_stack(process); }), dir.index());
add_file(create_generated_file("regs", [&process] { return procfs$pid_regs(process); }), dir.index());
add_file(create_generated_file("fds", [&process] { return procfs$pid_fds(process); }), dir.index());
add_file(create_generated_file("vm", [&process] (SynthFSInode&) { return procfs$pid_vm(process); }), dir.index());
add_file(create_generated_file("vmo", [&process] (SynthFSInode&) { return procfs$pid_vmo(process); }), dir.index());
add_file(create_generated_file("stack", [&process] (SynthFSInode&) { return procfs$pid_stack(process); }), dir.index());
add_file(create_generated_file("regs", [&process] (SynthFSInode&) { return procfs$pid_regs(process); }), dir.index());
add_file(create_generated_file("fds", [&process] (SynthFSInode&) { return procfs$pid_fds(process); }), dir.index());
if (process.executable_inode())
add_file(create_generated_file("exe", [&process] { return procfs$pid_exe(process); }, 00120777), dir.index());
add_file(create_generated_file("exe", [&process] (SynthFSInode&) { return procfs$pid_exe(process); }, 00120777), dir.index());
if (process.cwd_inode())
add_file(create_generated_file("cwd", [&process] { return procfs$pid_cwd(process); }, 00120777), dir.index());
add_file(create_generated_file("cwd", [&process] (SynthFSInode&) { return procfs$pid_cwd(process); }, 00120777), dir.index());
}
void ProcFS::remove_process(Process& process)
@ -179,7 +179,7 @@ void ProcFS::remove_process(Process& process)
m_pid2inode.remove(pid);
}
ByteBuffer procfs$mm()
ByteBuffer procfs$mm(SynthFSInode&)
{
// FIXME: Implement
InterruptDisabler disabler;
@ -198,7 +198,7 @@ ByteBuffer procfs$mm()
return builder.to_byte_buffer();
}
ByteBuffer procfs$mounts()
ByteBuffer procfs$mounts(SynthFSInode&)
{
InterruptDisabler disabler;
StringBuilder builder;
@ -213,7 +213,7 @@ ByteBuffer procfs$mounts()
return builder.to_byte_buffer();
}
ByteBuffer procfs$cpuinfo()
ByteBuffer procfs$cpuinfo(SynthFSInode&)
{
StringBuilder builder;
{
@ -276,7 +276,7 @@ ByteBuffer procfs$cpuinfo()
return builder.to_byte_buffer();
}
ByteBuffer procfs$kmalloc()
ByteBuffer procfs$kmalloc(SynthFSInode&)
{
StringBuilder builder;
builder.appendf(
@ -290,7 +290,7 @@ ByteBuffer procfs$kmalloc()
return builder.to_byte_buffer();
}
ByteBuffer procfs$summary()
ByteBuffer procfs$summary(SynthFSInode&)
{
InterruptDisabler disabler;
auto processes = Process::allProcesses();
@ -313,7 +313,7 @@ ByteBuffer procfs$summary()
return builder.to_byte_buffer();
}
ByteBuffer procfs$inodes()
ByteBuffer procfs$inodes(SynthFSInode&)
{
extern HashTable<Inode*>& all_inodes();
auto& vfs = VFS::the();
@ -326,6 +326,57 @@ ByteBuffer procfs$inodes()
return builder.to_byte_buffer();
}
struct SysVariableData final : public SynthFSInodeCustomData {
virtual ~SysVariableData() override { }
enum Type {
Invalid,
Boolean,
};
Type type { Invalid };
Function<void()> change_callback;
void* address;
};
static ByteBuffer read_sys_bool(SynthFSInode& inode)
{
ASSERT(inode.custom_data());
auto buffer = ByteBuffer::create_uninitialized(2);
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
ASSERT(custom_data.type == SysVariableData::Boolean);
ASSERT(custom_data.address);
buffer[0] = *reinterpret_cast<bool*>(custom_data.address) ? '1' : '0';
buffer[1] = '\n';
return buffer;
}
static ssize_t write_sys_bool(SynthFSInode& inode, const ByteBuffer& data)
{
ASSERT(inode.custom_data());
if (data.size() >= 1 && (data[0] == '0' || data[0] == '1')) {
auto& custom_data = *static_cast<const SysVariableData*>(inode.custom_data());
ASSERT(custom_data.address);
bool old_value = *reinterpret_cast<bool*>(custom_data.address);
bool new_value = data[0] == '1';
*reinterpret_cast<bool*>(custom_data.address) = new_value;
if (old_value != new_value && custom_data.change_callback)
custom_data.change_callback();
}
return data.size();
}
void ProcFS::add_sys_bool(String&& name, bool* var, Function<void()>&& change_callback)
{
auto file = create_generated_file(move(name), move(read_sys_bool), move(write_sys_bool));
auto data = make<SysVariableData>();
data->type = SysVariableData::Boolean;
data->change_callback = move(change_callback);
data->address = var;
file->set_custom_data(move(data));
InterruptDisabler disabler;
add_file(move(file), m_sys_dir.index());
}
bool ProcFS::initialize()
{
SynthFS::initialize();
@ -335,6 +386,7 @@ bool ProcFS::initialize()
add_file(create_generated_file("summary", procfs$summary));
add_file(create_generated_file("cpuinfo", procfs$cpuinfo));
add_file(create_generated_file("inodes", procfs$inodes));
m_sys_dir = add_file(create_directory("sys"));
return true;
}

View file

@ -18,9 +18,14 @@ public:
void add_process(Process&);
void remove_process(Process&);
void add_sys_file(String&&, Function<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback);
void add_sys_bool(String&&, bool*, Function<void()>&& change_callback = nullptr);
private:
ProcFS();
HashMap<pid_t, InodeIndex> m_pid2inode;
InodeIdentifier m_sys_dir;
};

View file

@ -167,9 +167,10 @@ ssize_t FileDescriptor::write(Process& process, const byte* data, size_t size)
// FIXME: What should happen to m_currentOffset?
return m_device->write(process, data, size);
}
// FIXME: Implement non-device writes.
ASSERT_NOT_REACHED();
return -1;
ASSERT(m_inode);
ssize_t nwritten = m_inode->write(ByteBuffer::wrap((byte*)data, size));
m_current_offset += nwritten;
return nwritten;
}
bool FileDescriptor::can_write(Process& process)

View file

@ -69,7 +69,7 @@ RetainPtr<SynthFSInode> SynthFS::create_text_file(String&& name, ByteBuffer&& co
return file;
}
RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer()>&& generator, Unix::mode_t mode)
RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& generator, Unix::mode_t mode)
{
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
file->m_generator = move(generator);
@ -82,6 +82,20 @@ RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<B
return file;
}
RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback, Unix::mode_t mode)
{
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
file->m_generator = move(read_callback);
file->m_write_callback = move(write_callback);
file->m_name = move(name);
file->m_metadata.size = 0;
file->m_metadata.uid = 0;
file->m_metadata.gid = 0;
file->m_metadata.mode = mode;
file->m_metadata.mtime = mepoch;
return file;
}
InodeIdentifier SynthFS::add_file(RetainPtr<SynthFSInode>&& file, InodeIndex parent)
{
ASSERT_INTERRUPTS_DISABLED();
@ -197,10 +211,10 @@ ssize_t SynthFSInode::read_bytes(Unix::off_t offset, size_t count, byte* buffer,
ByteBuffer generatedData;
if (m_generator) {
if (!descriptor) {
generatedData = m_generator();
generatedData = m_generator(*this);
} else {
if (!descriptor->generator_cache())
descriptor->generator_cache() = m_generator();
descriptor->generator_cache() = m_generator(*this);
generatedData = descriptor->generator_cache();
}
}
@ -259,10 +273,11 @@ void SynthFSInode::flush_metadata()
{
}
bool SynthFSInode::write(const ByteBuffer&)
bool SynthFSInode::write(const ByteBuffer& data)
{
ASSERT_NOT_REACHED();
return false;
if (!m_write_callback)
return 0; // FIXME: -EPERM?
return m_write_callback(*this, data);
}
bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error)
@ -274,3 +289,7 @@ bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte
ASSERT_NOT_REACHED();
return false;
}
SynthFSInodeCustomData::~SynthFSInodeCustomData()
{
}

View file

@ -28,7 +28,8 @@ protected:
RetainPtr<SynthFSInode> create_directory(String&& name);
RetainPtr<SynthFSInode> create_text_file(String&& name, ByteBuffer&&, Unix::mode_t = 0010644);
RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer()>&&, Unix::mode_t = 0100644);
RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Unix::mode_t = 0100644);
RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&&, Unix::mode_t = 0100644);
InodeIdentifier add_file(RetainPtr<SynthFSInode>&&, InodeIndex parent = RootInodeIndex);
bool remove_file(InodeIndex);
@ -38,11 +39,19 @@ private:
HashMap<InodeIndex, RetainPtr<SynthFSInode>> m_inodes;
};
struct SynthFSInodeCustomData {
virtual ~SynthFSInodeCustomData();
};
class SynthFSInode final : public Inode {
friend class SynthFS;
public:
virtual ~SynthFSInode() override;
void set_custom_data(OwnPtr<SynthFSInodeCustomData>&& custom_data) { m_custom_data = move(custom_data); }
SynthFSInodeCustomData* custom_data() { return m_custom_data.ptr(); }
const SynthFSInodeCustomData* custom_data() const { return m_custom_data.ptr(); }
private:
// ^Inode
virtual ssize_t read_bytes(Unix::off_t, size_t, byte* buffer, FileDescriptor*) override;
@ -62,9 +71,11 @@ private:
String m_name;
InodeIdentifier m_parent;
ByteBuffer m_data;
Function<ByteBuffer()> m_generator;
Function<ByteBuffer(SynthFSInode&)> m_generator;
Function<ssize_t(SynthFSInode&, const ByteBuffer&)> m_write_callback;
Vector<SynthFSInode*> m_children;
InodeMetadata m_metadata;
OwnPtr<SynthFSInodeCustomData> m_custom_data;
};
inline SynthFS& SynthFSInode::fs()

View file

@ -4,11 +4,11 @@
#include "WSEventLoop.h"
#include "Process.h"
#include "MemoryManager.h"
#include <Kernel/ProcFileSystem.h>
#include <Widgets/Painter.h>
#include <Widgets/CharacterBitmap.h>
#include <AK/StdLibExtras.h>
//#define DEBUG_FLUSH_YELLOW
//#define DEBUG_COUNTERS
static const int windowTitleBarHeight = 16;
@ -130,6 +130,8 @@ WSWindowManager::WSWindowManager()
m_cursor_bitmap_inner = CharacterBitmap::create_from_ascii(cursor_bitmap_inner_ascii, 12, 17);
m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17);
ProcFS::the().add_sys_bool("wm_flash_flush", &m_flash_flush);
invalidate();
compose();
}
@ -444,9 +446,8 @@ void WSWindowManager::flush(const Rect& a_rect)
const RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
size_t pitch = m_back_bitmap->pitch();
#ifdef DEBUG_FLUSH_YELLOW
if (m_flash_flush)
m_front_painter->fill_rect(rect, Color::Yellow);
#endif
for (int y = 0; y < rect.height(); ++y) {
fast_dword_copy(front_ptr, back_ptr, rect.width());

View file

@ -94,4 +94,6 @@ private:
OwnPtr<Painter> m_front_painter;
mutable Lock m_lock;
bool m_flash_flush { false };
};