Files
banan-os/kernel/kernel/Banos.cpp
T
Bananymous 4e9cfdde97 Kernel: Fix 32 bit target compilation
banos is written with only 64 bit in mind so it has to be disabled
2026-08-22 15:33:49 +03:00

229 lines
7.1 KiB
C++

#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>
#if ARCH(x86_64)
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() {
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;
}
}
#else
void Banos::initialize_initial_drivers()
{
}
BAN::ErrorOr<size_t> Banos::load_driver_from_image(const char* u_image)
{
(void)u_image;
return BAN::Error::from_errno(ENOTSUP);
}
#endif