Compare commits

...

3 Commits

Author SHA1 Message Date
f429e8c7bb driver-install: implemented a simple installer 2026-05-20 17:34:44 +03:00
cba2e8cfef Kernel: Implemented banos - a WIP C driver API
Banos is a stable WIP C driver API that is supposed to provide a simple
interface to interact with the kernel and load the modules dynamically.
It is WIP and atm this just implements module loading with a custom
banos_install syscall. Banos will not try to substitute parts of the
kernel instead it will just expose kernel functionality via a stable
BINARY API. Meaning binaries (should) remain forward and backward
compatible on a binary level.

Banos modules work similarly to those in linux, you expose symbols via
BANOS_EXPORT which allows you to export a name + addr paired symbol.
It puts it in the .banos-export section. Drivers provide metadata about
themselves in the REQUIRED .banos-driver section. Symbols are resolved
at runtime. The kernel exposes the driver functionality via the same
.banos-export export mechanism.

Banos modules are elf RELOCATABLE files (object files) which have
partial linking (only banos symbols should remain). Modules will
eventually define dependencies, will export symbols and will allow you
to build a complex object hierarchy.

This patch adds the banos_install syscall which takes in the driver
image to install and may only be executed by super users. The API
doesn't validate already loaded modules, as thats something the
userspace MAY choose to keep track of. Multi-instance functionality
shall be implemented via driver specific behaviuor (exposed in the dev
filesystem or some other means).

Modules are supposed to allow you to alter kernel behavior and extend
it, allowing you to create filesystems, drivers, networking
modifications, schedulers, probers, and more (hopefully) whilst
remaining binary compatible with any version of the kernel (again,
hopefully).
2026-05-20 17:34:42 +03:00
3ad67614aa Kernel: moved read/write_from_user out of Process 2026-05-20 17:34:39 +03:00
20 changed files with 489 additions and 47 deletions

View File

@@ -11,6 +11,7 @@ set(KERNEL_SOURCES
kernel/Audio/Controller.cpp kernel/Audio/Controller.cpp
kernel/Audio/HDAudio/AudioFunctionGroup.cpp kernel/Audio/HDAudio/AudioFunctionGroup.cpp
kernel/Audio/HDAudio/Controller.cpp kernel/Audio/HDAudio/Controller.cpp
kernel/Banos.cpp
kernel/BootInfo.cpp kernel/BootInfo.cpp
kernel/CPUID.cpp kernel/CPUID.cpp
kernel/Credentials.cpp kernel/Credentials.cpp
@@ -121,6 +122,7 @@ set(KERNEL_SOURCES
kernel/USB/USBManager.cpp kernel/USB/USBManager.cpp
kernel/USB/XHCI/Controller.cpp kernel/USB/XHCI/Controller.cpp
kernel/USB/XHCI/Device.cpp kernel/USB/XHCI/Device.cpp
kernel/UserCopy.cpp
icxxabi.cpp icxxabi.cpp
) )

View File

@@ -41,7 +41,18 @@ SECTIONS
{ {
g_kernel_writable_start = .; g_kernel_writable_start = .;
*(.data) *(.data)
. = ALIGN(8);
g_drv_builtin_begin = .;
KEEP(*(.banos-driver))
g_drv_builtin_end = .;
. = ALIGN(8);
g_banos_export = .;
KEEP(*(.banos-export))
g_banos_export_end = .;
} }
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET) .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
{ {
g_kernel_bss_start = .; g_kernel_bss_start = .;

View File

@@ -0,0 +1,27 @@
#pragma once
// Copyright (c) 2026 Dcraftbg
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "version.h"
#include "revision.h"
#define BANOS_DRIVER_REVISION_CURRENT 0
typedef struct Banos_Driver Banos_Driver;
struct Banos_Driver {
unsigned long driver_size;
banos_version_t minimal_banos_version;
const char* name;
const char* license;
banos_version_t version;
// NOTE: checkout BANOS_DRIVER_INSTANCE_SIZE.
// You may use this instance data for anything you wish to store.
// If you need more than that just allocate it on the heap or
// globally if you add the proper verification of having your driver run only
// within a single instance
int (*init)(Banos_Driver* drv);
int (*uninit)(Banos_Driver* drv);
};
#define BANOS_DRIVER_API static __attribute__((section(".banos-driver"), used, aligned(8)))

View File

@@ -0,0 +1,15 @@
#pragma once
// Copyright (c) 2026 Dcraftbg
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
typedef struct Banos_Symbol {
const char* name;
void* arg;
} Banos_Symbol;
#define BANOS_EXPORT_SYMBOL(symname, str, ptr) \
static __attribute__((section(".banos-export"), used, aligned(8))) Banos_Symbol __symbol_##symname = {\
.name = str, \
.arg = ptr \
};
#define BANOS_EXPORT(name) BANOS_EXPORT_SYMBOL(name, #name, (void*)&name)

View File

@@ -0,0 +1,13 @@
#pragma once
// Copyright (c) 2026 Dcraftbg
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef __cplusplus
extern "C" {
#endif
void banos_dprintln(const char* str);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,2 @@
#pragma once
typedef unsigned long banos_revision_t;

View File

@@ -0,0 +1,28 @@
#pragma once
// Copyright (c) 2026 Dcraftbg
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// [ 8 bit major ] [ 8 minor ] [ 16 patch]
typedef unsigned int banos_version_t;
#define BANOS_VERSION_MAJOR_SHIFT 24
#define BANOS_VERSION_MINOR_SHIFT 16
#define BANOS_VERSION_PATCH_SHIFT 0
#define BANOS_VERSION_MAJOR_MASK 0xFF
#define BANOS_VERSION_MINOR_MASK 0xFF
#define BANOS_VERSION_PATCH_MASK 0xFFFF
#define BANOS_VERSION_MAKE(major, minor, patch) \
(banos_version_t)( \
(((major) & BANOS_VERSION_MAJOR_MASK) << BANOS_VERSION_MAJOR_SHIFT) | \
(((minor) & BANOS_VERSION_MINOR_MASK) << BANOS_VERSION_MINOR_SHIFT) | \
(((patch) & BANOS_VERSION_PATCH_MASK) << BANOS_VERSION_PATCH_SHIFT) \
)
#define BANOS_VERSION_CURRENT BANOS_VERSION_MAKE(0, 0, 1)
#define BANOS_VERSION_GET_MAJOR(v) (((v) >> BANOS_VERSION_MAJOR_SHIFT) & BANOS_VERSION_MAJOR_MASK)
#define BANOS_VERSION_GET_MINOR(v) (((v) >> BANOS_VERSION_MINOR_SHIFT) & BANOS_VERSION_MINOR_MASK)
#define BANOS_VERSION_GET_PATCH(v) (((v) >> BANOS_VERSION_PATCH_SHIFT) & BANOS_VERSION_PATCH_MASK)

View File

@@ -0,0 +1,10 @@
#pragma once
#include <BAN/Vector.h>
#include <BAN/StringView.h>
typedef struct Banos_Symbol Banos_Symbol;
namespace Banos {
void* resolve_symbol(const char* name);
void import_symbols(Banos_Symbol* symbols, size_t count);
void initialize_initial_drivers(void);
BAN::ErrorOr<size_t> load_driver_from_image(const char* u_image);
}

View File

@@ -221,6 +221,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_load_keymap(const char* path); BAN::ErrorOr<long> sys_load_keymap(const char* path);
BAN::ErrorOr<long> sys_banos_install(const char* object);
BAN::RefPtr<TTY> controlling_terminal() { return m_controlling_terminal; } BAN::RefPtr<TTY> controlling_terminal() { return m_controlling_terminal; }
static Process& current() { return Thread::current().process(); } static Process& current() { return Thread::current().process(); }
@@ -284,9 +286,6 @@ namespace Kernel
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const; BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const; BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write); BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
uint64_t signal_pending_mask() const uint64_t signal_pending_mask() const

View File

@@ -0,0 +1,7 @@
#pragma once
#include <BAN/Errors.h>
namespace Kernel {
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
};

215
kernel/kernel/Banos.cpp Normal file
View File

@@ -0,0 +1,215 @@
#include <kernel/Debug.h>
#include <kernel/Banos.h>
#include <BAN/Assert.h>
#include <banos/driver.h>
#include <banos/print.h>
#include <banos/export.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/ELF.h>
#include <LibELF/Types.h>
#include <LibELF/Values.h>
#include <kernel/Process.h>
#include <BAN/HashMap.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/UserCopy.h>
using namespace LibELF;
using namespace Kernel;
extern "C" {
void banos_dprintln(const char* str) {
dprintln("{}", str);
}
void* banos_lookup_symbol(const char* str) {
return Banos::resolve_symbol(str);
}
}
BANOS_EXPORT(banos_dprintln);
BANOS_EXPORT(banos_lookup_symbol);
BAN::HashMap<BAN::StringView, void*> g_banos_symbols;
void* Banos::resolve_symbol(const char* name) {
auto it = g_banos_symbols.find(name);
return it == g_banos_symbols.end() ? NULL : it->value;
}
void Banos::import_symbols(Banos_Symbol* symbols, size_t count) {
for(size_t i = 0; i < count; ++i) {
auto sym = symbols + i;
MUST(g_banos_symbols.insert(sym->name, sym->arg));
}
}
// TODO: driver unloading with a reference counter
struct Driver_Instance {
Banos_Driver* drv;
};
static BAN::Vector<Driver_Instance> s_driver_instaces;
static SpinLock s_driver_instaces_lock;
extern Banos_Symbol g_banos_export[],
g_banos_export_end[];
static void load_drv(Banos_Driver* drv) {
ASSERT(drv->driver_size >= sizeof(Banos_Driver));
dprintln("Loading driver:");
dprintln(" name: {}", drv->name);
if(drv->license) dprintln(" license: {}", drv->license);
dprintln(" version: {}.{}.{}", BANOS_VERSION_GET_MAJOR(drv->version), BANOS_VERSION_GET_MINOR(drv->version), BANOS_VERSION_GET_PATCH(drv->version));
int e = drv->init(drv);
if(e < 0) dprintln(" Failed to init {} => {}", drv->name, -e);
}
BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image) {
if(!Process::current().credentials().is_superuser()) return BAN::Error::from_errno(EPERM);
// TODO: permission verification. Only root should be allowed to do this
LibELF::ElfNativeFileHeader header;
const unsigned char elf_class =
#if ARCH(i686)
ELFCLASS32;
#elif ARCH(x86_64)
ELFCLASS64;
#else
# error update elf class
#endif
// TODO: is banan-os really ever gonna be running on MSB machines?
const unsigned char elf_data = ELFDATA2LSB;
// TODO: do we need to verify e_machine? I mean we do not really care.
// But I'm leaving this todo:
// Look up EM_X86_64 and EM_360|EM_860|EM_960
TRY(read_from_user(u_image, &header, sizeof header));
if( header.e_ident[EI_MAG0] != ELFMAG0 ||
header.e_ident[EI_MAG1] != ELFMAG1 ||
header.e_ident[EI_MAG2] != ELFMAG2 ||
header.e_ident[EI_MAG3] != ELFMAG3 ||
header.e_ident[EI_CLASS] != elf_class ||
header.e_ident[EI_DATA] != elf_data ||
header.e_ident[EI_VERSION] != EV_CURRENT ||
header.e_type != ET_REL ||
header.e_version != EV_CURRENT ||
header.e_ehsize != sizeof(header) ||
header.e_shentsize != sizeof(ElfNativeSectionHeader))
return BAN::Error::from_errno(EINVAL);
BAN::Vector<LibELF::ElfNativeSectionHeader> secs(header.e_shnum);
TRY(read_from_user(u_image + header.e_shoff, secs.data(), secs.size() * sizeof(*secs.data())));
auto shstr = secs[header.e_shstrndx];
size_t total_size = 0;
LibELF::ElfNativeSectionHeader *strtab = nullptr,
*symtab = nullptr,
*driver_section = nullptr;
for(auto& sec : secs) {
if(sec.sh_flags & LibELF::SHF_ALLOC) {
sec.sh_addr = total_size;
total_size += sec.sh_size;
}
if(sec.sh_name == 0) continue;
char name[256];
TRY(read_string_from_user(u_image + shstr.sh_offset + sec.sh_name, name, sizeof name));
BAN::StringView name_sv(name);
if(sec.sh_type == LibELF::SHT_SYMTAB) {
symtab = &sec;
}
// TODO: verify sh_type for both of these?
if(name_sv == ".strtab") {
strtab = &sec;
} else if(name_sv == ".banos-driver") {
driver_section = &sec;
}
}
if(!symtab || !strtab || !driver_section)
return BAN::Error::from_errno(EINVAL);
total_size += PAGE_SIZE;
total_size &= ~(PAGE_SIZE-1);
auto driver = TRY(VirtualRange::create_to_vaddr_range(PageTable::kernel(), { KERNEL_OFFSET, UINTPTR_MAX }, total_size, PageTable::Execute | PageTable::ReadWrite | PageTable::Present, true));
for(auto& sec : secs) {
if(sec.sh_flags & LibELF::SHF_ALLOC) {
sec.sh_addr += driver->vaddr();
}
}
Banos_Driver* banos_driver = reinterpret_cast<Banos_Driver*>(driver_section->sh_addr);
for(auto& sec : secs) {
if(sec.sh_name == 0) continue;
if(sec.sh_flags & LibELF::SHF_ALLOC) {
TRY(read_from_user(u_image + sec.sh_offset, reinterpret_cast<char*>(sec.sh_addr), sec.sh_size));
}
if(sec.sh_type == LibELF::SHT_RELA) {
auto& link_sec = secs[sec.sh_info];
size_t rela_count = sec.sh_size/sizeof(LibELF::ElfNativeRelocationA);
BAN::Vector<LibELF::ElfNativeRelocationA> rela_data(rela_count);
TRY(read_from_user(u_image + sec.sh_offset, rela_data.data(), rela_count * sizeof *rela_data.data()));
for(auto rela : rela_data) {
auto type = ELF64_R_TYPE(rela.r_info);
auto symbol = ELF64_R_SYM(rela.r_info);
vaddr_t value = 0;
LibELF::ElfNativeSymbol sym;
TRY(read_from_user(u_image + symtab->sh_offset + sizeof(sym) * symbol, &sym, sizeof sym));
if(sym.st_shndx) {
value = secs[sym.st_shndx].sh_addr;
} else {
char name[256];
TRY(read_string_from_user(u_image + strtab->sh_offset + sym.st_name, name, sizeof name));
value = reinterpret_cast<vaddr_t>(Banos::resolve_symbol(name));
if(!value) {
derrorln("Failed to find symbol {}", name);
return BAN::Error::from_errno(ENOENT);
}
}
vaddr_t at = link_sec.sh_addr + rela.r_offset;
size_t size = 0;
switch(type) {
case LibELF::R_X86_64_PLT32:
case LibELF::R_X86_64_PC32:
value -= at;
// fallthrough
case LibELF::R_X86_64_32:
case LibELF::R_X86_64_32S:
value += rela.r_addend;
size = sizeof(uint32_t);
break;
case LibELF::R_X86_64_64:
value += rela.r_addend;
size = sizeof(uint64_t);
break;
default:
derrorln("TODO: Unsupported relocation type {}", type);
return BAN::Error::from_errno(ENOSYS);
}
switch(size) {
case 4: *reinterpret_cast<uint32_t*>(at) = value; break;
case 8: *reinterpret_cast<uint64_t*>(at) = value; break;
}
}
}
}
Driver_Instance instance;
instance.drv = banos_driver;
load_drv(instance.drv);
SpinLockGuard _(s_driver_instaces_lock);
TRY(s_driver_instaces.push_back(instance));
// TODO: import symbols and resolve redefintions :)
return s_driver_instaces.size() - 1;
}
// NOTE: should be more than plenty ;)
extern char g_drv_builtin_begin[];
extern char g_drv_builtin_end[];
void Banos::initialize_initial_drivers(void) {
import_symbols(g_banos_export, g_banos_export_end - g_banos_export);
char* head = g_drv_builtin_begin;
while(head < g_drv_builtin_end) {
Banos_Driver* drv = (Banos_Driver*)head;
load_drv(drv);
head += drv->driver_size;
}
}

View File

@@ -4,6 +4,7 @@
#include <kernel/Networking/NetworkManager.h> #include <kernel/Networking/NetworkManager.h>
#include <kernel/OpenFileDescriptorSet.h> #include <kernel/OpenFileDescriptorSet.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/UserCopy.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/file.h> #include <sys/file.h>
@@ -254,7 +255,7 @@ namespace Kernel
if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK) if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK)
{ {
struct flock flock; struct flock flock;
TRY(Process::current().read_from_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock))); TRY(read_from_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
flock.l_pid = Process::current().pid(); flock.l_pid = Process::current().pid();
BAN::RefPtr<Inode> inode; BAN::RefPtr<Inode> inode;
@@ -307,7 +308,7 @@ namespace Kernel
} }
if (cmd == F_GETLK) if (cmd == F_GETLK)
TRY(Process::current().write_to_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock))); TRY(write_to_user(reinterpret_cast<void*>(extra), &flock, sizeof(struct flock)));
return 0; return 0;
} }

View File

@@ -20,7 +20,9 @@
#include <kernel/Storage/StorageDevice.h> #include <kernel/Storage/StorageDevice.h>
#include <kernel/Terminal/PseudoTerminal.h> #include <kernel/Terminal/PseudoTerminal.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#include <kernel/UserCopy.h>
#include <kernel/Banos.h>
#include <LibELF/AuxiliaryVector.h> #include <LibELF/AuxiliaryVector.h>
#include <LibInput/KeyboardLayout.h> #include <LibInput/KeyboardLayout.h>
@@ -3885,47 +3887,6 @@ namespace Kernel
return region->allocate_page_containing(address, wants_write); return region->allocate_page_containing(address, wants_write);
} }
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
static inline bool is_valid_user_address(const void* user_addr, size_t size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
return false;
if (user_vaddr + size > USERSPACE_END)
return false;
return true;
}
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
{
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(out, user_addr, size))
return BAN::Error::from_errno(EFAULT);
return {};
}
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
{
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
if (!is_valid_user_address(user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_strncpy(out, user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
return {};
}
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
{
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(user_addr, in, size))
return BAN::Error::from_errno(EFAULT);
return {};
}
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write) BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
{ {
// TODO: allow pinning multiple regions? // TODO: allow pinning multiple regions?
@@ -3990,4 +3951,7 @@ namespace Kernel
return BAN::Error::from_errno(EFAULT); return BAN::Error::from_errno(EFAULT);
} }
BAN::ErrorOr<long> Process::sys_banos_install(const char* u_image) {
return TRY(Banos::load_driver_from_image(u_image));
}
} }

View File

@@ -9,6 +9,7 @@
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#include <kernel/UserCopy.h>
namespace Kernel namespace Kernel
{ {
@@ -727,7 +728,7 @@ namespace Kernel
{ {
static_assert(sizeof(T) >= sizeof(uintptr_t)); static_assert(sizeof(T) >= sizeof(uintptr_t));
sp -= sizeof(T); sp -= sizeof(T);
if (m_process->write_to_user(reinterpret_cast<void*>(sp), &value, sizeof(T)).is_error()) if (write_to_user(reinterpret_cast<void*>(sp), &value, sizeof(T)).is_error())
m_process->exit(128 + SIGSEGV, SIGSEGV | 0x80); m_process->exit(128 + SIGSEGV, SIGSEGV | 0x80);
}; };

View File

@@ -0,0 +1,40 @@
#include <kernel/UserCopy.h>
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
static inline bool is_valid_user_address(const void* user_addr, size_t size)
{
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
return false;
if (user_vaddr + size > USERSPACE_END)
return false;
return true;
}
BAN::ErrorOr<void> Kernel::read_from_user(const void* user_addr, void* out, size_t size)
{
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(out, user_addr, size))
return BAN::Error::from_errno(EFAULT);
return {};
}
BAN::ErrorOr<void> Kernel::read_string_from_user(const char* user_addr, char* out, size_t max_size)
{
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
if (!is_valid_user_address(user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_strncpy(out, user_addr, max_size))
return BAN::Error::from_errno(EFAULT);
return {};
}
BAN::ErrorOr<void> Kernel::write_to_user(void* user_addr, const void* in, size_t size)
{
if (!is_valid_user_address(user_addr, size))
return BAN::Error::from_errno(EFAULT);
if (!safe_user_memcpy(user_addr, in, size))
return BAN::Error::from_errno(EFAULT);
return {};
}

View File

@@ -27,6 +27,7 @@
#include <kernel/Terminal/VirtualTTY.h> #include <kernel/Terminal/VirtualTTY.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#include <kernel/USB/USBManager.h> #include <kernel/USB/USBManager.h>
#include <kernel/Banos.h>
#include <LibInput/KeyboardLayout.h> #include <LibInput/KeyboardLayout.h>
@@ -261,6 +262,8 @@ static void init2(void*)
TTY::initialize_devices(); TTY::initialize_devices();
Banos::initialize_initial_drivers();
auto console_path = MUST(BAN::String::formatted("/dev/{}", cmdline.console)); auto console_path = MUST(BAN::String::formatted("/dev/{}", cmdline.console));
auto console_path_sv = console_path.sv(); auto console_path_sv = console_path.sv();
MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"_sv, BAN::Span<BAN::StringView>(&console_path_sv, 1))); MUST(Process::create_userspace({ 0, 0, 0, 0 }, "/usr/bin/init"_sv, BAN::Span<BAN::StringView>(&console_path_sv, 1)));

View File

@@ -117,6 +117,7 @@ __BEGIN_DECLS
O(SYS_SETGROUPS, setgroups) \ O(SYS_SETGROUPS, setgroups) \
O(SYS_CHROOT, chroot) \ O(SYS_CHROOT, chroot) \
O(SYS_EVENTFD, eventfd) \ O(SYS_EVENTFD, eventfd) \
O(SYS_BANOS_INSTALL, banos_install) \
enum Syscall enum Syscall
{ {

View File

@@ -57,6 +57,7 @@ set(USERSPACE_PROGRAMS
whoami whoami
WindowServer WindowServer
yes yes
driver-install
) )
foreach(project ${USERSPACE_PROGRAMS}) foreach(project ${USERSPACE_PROGRAMS})

View File

@@ -0,0 +1,9 @@
set(SOURCES
main.cpp
)
add_executable(driver-install ${SOURCES})
banan_link_library(driver-install ban)
banan_link_library(driver-install libc)
install(TARGETS driver-install OPTIONAL)

View File

@@ -0,0 +1,93 @@
#include <stdio.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
char* g_exe;
char* shift_args(int *argc, char ***argv) {
return (assert((*argc) > 0), ((*argc)--, *((*argv)++)));
}
void help(FILE* sink) {
fprintf(sink, "%s <input filename>\n", g_exe);
}
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define eprintfln(fmt, ...) eprintf(fmt "\n", ## __VA_ARGS__)
char* read_entire_file(const char* path) {
char* result = NULL;
char* head = NULL;
char* end = NULL;
size_t buf_size = 0;
long at = 0;
FILE *f = fopen(path, "rb");
if(!f) {
fprintf(stderr, "ERROR Could not open file %s: %s\n",path,strerror(errno));
return NULL;
}
if(fseek(f, 0, SEEK_END) != 0) {
fprintf(stderr, "ERROR Could not fseek on file %s: %s\n",path,strerror(errno));
result = NULL; goto DEFER;
}
at = ftell(f);
if(at == -1L) {
fprintf(stderr, "ERROR Could not ftell on file %s: %s\n",path,strerror(errno));
result = NULL; goto DEFER;
}
buf_size = at+1;
rewind(f);
result = (char*)malloc(buf_size);
assert(result && "Ran out of memory");
head = result;
end = result+buf_size-1;
while(head != end) {
head += fread(head, 1, end-head, f);
if(ferror(f)) {
fprintf(stderr, "ERROR Could not fread on file %s: %s\n",path,strerror(errno));
free(result);
result = NULL; goto DEFER;
}
}
result[buf_size-1] = '\0';
DEFER:
fclose(f);
return result;
}
static int banos_install(const void* driver_image) {
return syscall(SYS_BANOS_INSTALL, driver_image);
}
int main(int argc, char** argv)
{
g_exe = shift_args(&argc, &argv);
char* input_filename = NULL;
while(argc > 0) {
char* arg = shift_args(&argc, &argv);
if(!input_filename) input_filename = arg;
else {
eprintfln("ERROR: Unexpected argument `%s'", arg);
help(stderr);
return 1;
}
}
if(!input_filename) {
eprintfln("ERROR: Missing input filename!");
help(stderr);
return 1;
}
char* data = read_entire_file(input_filename);
if(!data) return 1;
int id = banos_install(data);
if(id == -1) {
eprintfln("ERROR: Failed to install driver `%s': %s", input_filename, strerror(errno));
return 1;
}
printf("%d\n", id);
return 0;
}