Compare commits
3 Commits
f429e8c7bb
...
77796dd317
| Author | SHA1 | Date | |
|---|---|---|---|
| 77796dd317 | |||
| f1a72cc9da | |||
| 718379ce3b |
@@ -11,6 +11,7 @@ set(KERNEL_SOURCES
|
||||
kernel/Audio/Controller.cpp
|
||||
kernel/Audio/HDAudio/AudioFunctionGroup.cpp
|
||||
kernel/Audio/HDAudio/Controller.cpp
|
||||
kernel/Banos.cpp
|
||||
kernel/BootInfo.cpp
|
||||
kernel/CPUID.cpp
|
||||
kernel/Credentials.cpp
|
||||
@@ -121,6 +122,7 @@ set(KERNEL_SOURCES
|
||||
kernel/USB/USBManager.cpp
|
||||
kernel/USB/XHCI/Controller.cpp
|
||||
kernel/USB/XHCI/Device.cpp
|
||||
kernel/UserCopy.cpp
|
||||
icxxabi.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -41,7 +41,18 @@ SECTIONS
|
||||
{
|
||||
g_kernel_writable_start = .;
|
||||
*(.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)
|
||||
{
|
||||
g_kernel_bss_start = .;
|
||||
|
||||
27
kernel/include/banos/driver.h
Normal file
27
kernel/include/banos/driver.h
Normal 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)))
|
||||
15
kernel/include/banos/export.h
Normal file
15
kernel/include/banos/export.h
Normal 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)
|
||||
13
kernel/include/banos/print.h
Normal file
13
kernel/include/banos/print.h
Normal 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
|
||||
2
kernel/include/banos/revision.h
Normal file
2
kernel/include/banos/revision.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
typedef unsigned long banos_revision_t;
|
||||
28
kernel/include/banos/version.h
Normal file
28
kernel/include/banos/version.h
Normal 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)
|
||||
10
kernel/include/kernel/Banos.h
Normal file
10
kernel/include/kernel/Banos.h
Normal 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);
|
||||
}
|
||||
@@ -221,6 +221,8 @@ namespace Kernel
|
||||
|
||||
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; }
|
||||
|
||||
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<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);
|
||||
|
||||
uint64_t signal_pending_mask() const
|
||||
|
||||
12
kernel/include/kernel/UserCopy.h
Normal file
12
kernel/include/kernel/UserCopy.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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
215
kernel/kernel/Banos.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/OpenFileDescriptorSet.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
@@ -254,7 +255,7 @@ namespace Kernel
|
||||
if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK)
|
||||
{
|
||||
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();
|
||||
|
||||
BAN::RefPtr<Inode> inode;
|
||||
@@ -307,7 +308,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include <kernel/Storage/StorageDevice.h>
|
||||
#include <kernel/Terminal/PseudoTerminal.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
#include <kernel/Banos.h>
|
||||
#include <LibELF/AuxiliaryVector.h>
|
||||
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
@@ -3885,47 +3887,6 @@ namespace Kernel
|
||||
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)
|
||||
{
|
||||
// TODO: allow pinning multiple regions?
|
||||
@@ -3990,4 +3951,7 @@ namespace Kernel
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <kernel/Scheduler.h>
|
||||
#include <kernel/Thread.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/UserCopy.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
@@ -727,7 +728,7 @@ namespace Kernel
|
||||
{
|
||||
static_assert(sizeof(T) >= sizeof(uintptr_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);
|
||||
};
|
||||
|
||||
|
||||
48
kernel/kernel/UserCopy.cpp
Normal file
48
kernel/kernel/UserCopy.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <kernel/Memory/Types.h>
|
||||
#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);
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
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> 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> 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> 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 {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <kernel/Terminal/VirtualTTY.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
#include <kernel/USB/USBManager.h>
|
||||
#include <kernel/Banos.h>
|
||||
|
||||
#include <LibInput/KeyboardLayout.h>
|
||||
|
||||
@@ -261,6 +262,8 @@ static void init2(void*)
|
||||
|
||||
TTY::initialize_devices();
|
||||
|
||||
Banos::initialize_initial_drivers();
|
||||
|
||||
auto console_path = MUST(BAN::String::formatted("/dev/{}", cmdline.console));
|
||||
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)));
|
||||
|
||||
@@ -117,6 +117,7 @@ __BEGIN_DECLS
|
||||
O(SYS_SETGROUPS, setgroups) \
|
||||
O(SYS_CHROOT, chroot) \
|
||||
O(SYS_EVENTFD, eventfd) \
|
||||
O(SYS_BANOS_INSTALL, banos_install) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
||||
@@ -57,6 +57,7 @@ set(USERSPACE_PROGRAMS
|
||||
whoami
|
||||
WindowServer
|
||||
yes
|
||||
driver-install
|
||||
)
|
||||
|
||||
foreach(project ${USERSPACE_PROGRAMS})
|
||||
|
||||
9
userspace/programs/driver-install/CMakeLists.txt
Normal file
9
userspace/programs/driver-install/CMakeLists.txt
Normal 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)
|
||||
93
userspace/programs/driver-install/main.cpp
Normal file
93
userspace/programs/driver-install/main.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user