sys/mod: Basic kernel module loading

This commit is contained in:
Mark Poliakov 2024-04-01 17:23:12 +03:00
parent 35a44a8ca1
commit 39956dedb8
53 changed files with 1592 additions and 142 deletions

80
Cargo.lock generated
View File

@ -57,6 +57,18 @@ dependencies = [
"log",
]
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
@ -310,6 +322,15 @@ version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "dependency-graph"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5143247629540606d0888beae9ca0e0b9a81a32151bfecd0b2be4a961155c24d"
dependencies = [
"petgraph",
]
[[package]]
name = "device-api"
version = "0.1.0"
@ -474,6 +495,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "fnv"
version = "1.0.7"
@ -759,6 +786,7 @@ version = "0.1.0"
dependencies = [
"abi-lib",
"atomic_enum",
"bytemuck",
"cfg-if",
"crossbeam-queue",
"device-api",
@ -791,6 +819,7 @@ dependencies = [
"kernel-arch",
"libk-mm-interface",
"libk-util",
"linked_list_allocator",
"log",
"vmalloc",
"yggdrasil-abi",
@ -810,6 +839,7 @@ dependencies = [
name = "libk-util"
version = "0.1.0"
dependencies = [
"ahash",
"crossbeam-queue",
"futures-util",
"kernel-arch",
@ -998,6 +1028,16 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "petgraph"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap",
]
[[package]]
name = "pin-project-lite"
version = "0.2.13"
@ -1190,7 +1230,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
"semver 0.9.0",
]
[[package]]
@ -1254,6 +1294,15 @@ dependencies = [
"semver-parser",
]
[[package]]
name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
dependencies = [
"serde",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
@ -1509,6 +1558,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vmalloc"
version = "0.1.0"
@ -1700,10 +1755,12 @@ name = "xtask"
version = "0.1.0"
dependencies = [
"clap",
"dependency-graph",
"env_logger",
"git2",
"log",
"qemu",
"semver 1.0.22",
"serde",
"tar",
"thiserror",
@ -1915,7 +1972,6 @@ dependencies = [
"libk-device",
"libk-mm",
"libk-util",
"linked_list_allocator",
"log",
"memfs",
"memtables",
@ -1951,3 +2007,23 @@ dependencies = [
"rustc-std-workspace-core",
"yggdrasil-abi",
]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
]

View File

@ -5,7 +5,7 @@ exclude = [
"boot/yboot-proto",
"tool/abi-generator",
"toolchain",
"userspace/dynload-program"
"userspace/dynload-program",
]
members = [
"xtask",

View File

@ -214,7 +214,7 @@ impl Object {
let reserved_addr = bs
.allocate_pages(
AllocateType::Address(image_start),
MemoryType::RUNTIME_SERVICES_DATA,
MemoryType::LOADER_DATA,
(image_end - image_start) as usize / 0x1000,
)
.expect("Could not allocate memory for kernel image");

View File

@ -12,15 +12,11 @@
"executables": true,
"panic-strategy": "abort",
"features": "-avx,-sse,+soft-float",
"dynamic-linking": true,
"relocation-model": "pic",
"has-thread-local": false,
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": [
"-Tetc/x86_64-unknown-none.ld"
]
}
"linker-flavor": "ld.lld"
}

View File

@ -5,7 +5,6 @@ KERNEL_VIRT_OFFSET = 0xFFFFFF8000000000;
SECTIONS {
. = KERNEL_PHYS_BASE;
PROVIDE(__kernel_phys_start = .);
PROVIDE(__kernel_start = . + KERNEL_VIRT_OFFSET);
.text.entry : {
@ -19,6 +18,10 @@ SECTIONS {
*(.text*)
}
.export.text : AT(. - KERNEL_VIRT_OFFSET) {
KEEP(*(.export.text*))
}
. = ALIGN(4K);
.rodata : AT(. - KERNEL_VIRT_OFFSET) {
*(.eh_frame*)
@ -46,5 +49,4 @@ SECTIONS {
PROVIDE(__bss_end_phys = . - KERNEL_VIRT_OFFSET);
PROVIDE(__kernel_end = .);
PROVIDE(__kernel_size = . - KERNEL_VIRT_OFFSET - KERNEL_PHYS_BASE);
};

View File

@ -39,7 +39,6 @@ memfs = { path = "driver/fs/memfs" }
atomic_enum = "0.2.0"
bitflags = "2.3.3"
linked_list_allocator = "0.10.5"
spinning_top = "0.2.5"
static_assertions = "1.1.0"
tock-registers = "0.8.1"

View File

@ -33,7 +33,7 @@ cfg_if! {
pub use imp::{ArchitectureImpl, KernelTableManagerImpl, ProcessAddressSpaceImpl, TaskContextImpl};
pub use kernel_arch_interface::{guard, mem, sync, task, util, Architecture};
pub use kernel_arch_interface::{guard, mem, sync, task, util, Architecture, KERNEL_VIRT_OFFSET};
pub type CpuImpl<S> = kernel_arch_interface::cpu::CpuImpl<ArchitectureImpl, S>;
pub type LocalCpuImpl<'a, S> = kernel_arch_interface::cpu::LocalCpuImpl<'a, ArchitectureImpl, S>;

View File

@ -62,9 +62,6 @@
.section .text
__x86_64_task_enter_from_fork:
// TODO
jmp .
xorq %rax, %rax
xorq %rcx, %rcx

View File

@ -0,0 +1,6 @@
[package]
name = "module-build"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,19 @@
use std::env;
pub fn build() {
let libk_so = env::var("MOD_LIBK_SO").expect("module-build: $MOD_LIBK_SO is not set");
println!("cargo:rerun-if-changed={}", libk_so);
println!("cargo:rerun-if-env-changed=MOD_LIBK_SO");
println!("cargo:rerun-if-env-changed=MOD_DEPENDENCIES");
if let Ok(deps) = env::var("MOD_DEPENDENCIES") {
let deps = deps.trim();
if !deps.is_empty() {
let deps = deps.split(':');
for dep in deps {
let (_, path) = dep.split_once("=").unwrap();
println!("cargo:rerun-if-changed={}", path);
}
}
}
}

View File

@ -1,9 +1,14 @@
cargo-features = ["profile-rustflags"]
[package]
name = "libk"
version = "0.1.0"
edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[lib]
crate_type = ["rlib", "dylib"]
[dependencies]
libk-mm = { path = "libk-mm" }
libk-util = { path = "libk-util" }
@ -22,9 +27,13 @@ crossbeam-queue = { version = "0.3.8", default-features = false, features = ["al
serde_json = { version = "1.0.111", default-features = false, features = ["alloc"] }
serde = { version = "1.0.193", features = ["derive"], default-features = false }
bytemuck = { version = "1.14.0", features = ["derive"] }
[dependencies.elf]
version = "0.7.2"
git = "https://git.alnyan.me/yggdrasil/yggdrasil-elf.git"
default-features = false
features = ["no_std_stream"]
[profile.dev]
rustflags = ["-Clink-dead-code=yes -Zexport-executable-symbols -Cprefer-dynamic"]

View File

@ -12,4 +12,5 @@ libk-util = { path = "../libk-util" }
libk-mm-interface = { path = "interface" }
vmalloc = { path = "../../lib/vmalloc" }
linked_list_allocator = "0.10.5"
log = "0.4.20"

View File

@ -0,0 +1,66 @@
//! Kernel's global heap allocator
use core::{
alloc::{GlobalAlloc, Layout},
ops::Range,
ptr::{null_mut, NonNull},
};
use libk_util::sync::IrqSafeSpinlock;
use linked_list_allocator::Heap;
/// Kernel heap manager
pub struct KernelAllocator {
inner: IrqSafeSpinlock<Heap>,
}
impl KernelAllocator {
const fn empty() -> Self {
Self {
inner: IrqSafeSpinlock::new(Heap::empty()),
}
}
unsafe fn init(&self, base: usize, size: usize) {
self.inner.lock().init(base as _, size);
}
fn range(&self) -> Range<usize> {
let lock = self.inner.lock();
lock.bottom() as usize..lock.top() as usize
}
}
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
match self.inner.lock().allocate_first_fit(layout) {
Ok(v) => v.as_ptr(),
Err(e) => {
log::error!("Failed to allocate {:?}: {:?}", layout, e);
null_mut()
}
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let ptr = NonNull::new(ptr).unwrap();
self.inner.lock().deallocate(ptr, layout)
}
}
/// Kernel's global allocator
#[global_allocator]
pub static GLOBAL_HEAP: KernelAllocator = KernelAllocator::empty();
/// Sets up kernel's global heap with given memory range.
///
/// # Safety
///
/// The caller must ensure the range is valid and mapped virtual memory.
pub unsafe fn init_heap(heap_base: usize, heap_size: usize) {
GLOBAL_HEAP.init(heap_base, heap_size);
}
/// Returns the heap address range
pub fn heap_range() -> Range<usize> {
GLOBAL_HEAP.range()
}

View File

@ -27,6 +27,7 @@ use yggdrasil_abi::error::Error;
pub mod address;
pub mod device;
pub mod heap;
pub mod phys;
pub mod pointer;
pub mod process;

View File

@ -1,6 +1,6 @@
use core::ops::Range;
use kernel_arch::{absolute_address, mem::PhysicalMemoryAllocator};
use kernel_arch::mem::PhysicalMemoryAllocator;
use libk_mm_interface::address::{FromRaw, IntoRaw, PhysicalAddress};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use yggdrasil_abi::{error::Error, system::SystemMemoryStats};
@ -221,13 +221,18 @@ pub unsafe fn init_from_iter<
}
fn kernel_physical_memory_region() -> PhysicalMemoryRegion {
use core::ptr::addr_of;
extern "C" {
static __kernel_phys_start: u8;
static __kernel_size: u8;
static __kernel_start: u8;
static __kernel_end: u8;
}
let base = PhysicalAddress::from_raw(absolute_address!(__kernel_phys_start));
let size = absolute_address!(__kernel_size);
let start = unsafe { addr_of!(__kernel_start) };
let end = unsafe { addr_of!(__kernel_end) };
let base = PhysicalAddress::from_raw(start.addr() - kernel_arch::KERNEL_VIRT_OFFSET);
let size = end.addr() - start.addr();
PhysicalMemoryRegion { base, size }
}

View File

@ -12,3 +12,4 @@ kernel-arch = { path = "../../arch" }
log = "0.4.20"
crossbeam-queue = { version = "0.3.8", default-features = false, features = ["alloc"] }
futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] }
ahash = { version = "0.8.11", default-features = false, features = ["no-rng"] }

View File

@ -0,0 +1,64 @@
use core::{
borrow::Borrow,
hash::{BuildHasher, Hash},
};
use alloc::vec::Vec;
pub type DefaultHashBuilder = core::hash::BuildHasherDefault<ahash::AHasher>;
pub type DefaultHashTable<K, V, const N: usize = 32> = HashTable<K, V, DefaultHashBuilder, N>;
pub struct HashTable<K, V, H = DefaultHashBuilder, const N: usize = 32>
where
[Vec<(K, V)>; N]: Sized,
{
buckets: [Vec<(K, V)>; N],
hasher: H,
}
impl<K, V, const N: usize> HashTable<K, V, DefaultHashBuilder, N>
where
[Vec<(K, V)>; N]: Sized,
{
pub const fn new() -> Self {
Self {
buckets: [const { Vec::new() }; N],
hasher: DefaultHashBuilder::default(),
}
}
}
impl<K: Hash + Eq, V, const N: usize> HashTable<K, V, DefaultHashBuilder, N> {
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
let h = self.hasher.hash_one(&key);
let bucket = &mut self.buckets[h as usize % self.buckets.len()];
if let Some((_, slot)) = bucket.iter_mut().find(|(k, _)| k == &key) {
Some(core::mem::replace(slot, value))
} else {
bucket.push((key, value));
None
}
}
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
Q: Hash + Eq + ?Sized,
K: Borrow<Q>,
{
self.get_key_value(key).map(|p| p.1)
}
pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
Q: Hash + Eq + ?Sized,
K: Borrow<Q>,
{
let h = self.hasher.hash_one(key);
let bucket = &self.buckets[h as usize % self.buckets.len()];
bucket
.iter()
.find_map(|(k, v)| (k.borrow() == key).then_some((k, v)))
}
}

View File

@ -1,5 +1,13 @@
#![no_std]
#![feature(maybe_uninit_slice, new_uninit, allocator_api, let_chains)]
#![feature(
maybe_uninit_slice,
new_uninit,
allocator_api,
let_chains,
inline_const,
const_trait_impl,
effects
)]
extern crate alloc;
@ -10,6 +18,7 @@ use core::{
};
pub mod event;
pub mod hash_table;
pub mod io;
pub mod queue;
pub mod ring;

View File

@ -23,11 +23,17 @@
)]
extern crate alloc;
extern crate serde;
pub use log;
pub use yggdrasil_abi::error;
#[macro_use]
pub mod task;
pub mod arch;
pub mod module;
pub mod panic;
pub mod random;
pub mod vfs;

218
kernel/libk/src/module.rs Normal file
View File

@ -0,0 +1,218 @@
use core::mem::size_of;
use alloc::{string::String, vec, vec::Vec};
use bytemuck::{Pod, Zeroable};
use elf::io_traits::{InputStream, SeekFrom};
use libk_mm::PageBox;
use libk_util::{hash_table::DefaultHashTable, io::Read, sync::LockMethod, OneTimeInit};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
path::Path,
};
use crate::{
task::{
binary::{
self,
elf::{ElfSegment, ElfSegmentType},
},
sync::Mutex,
},
vfs::{FileRef, IoContext},
};
#[derive(Clone, Copy, Debug, Zeroable, Pod)]
#[repr(C)]
pub struct Symbol {
pub st_name: u32,
pub st_info: u8,
pub st_other: u8,
pub st_shndx: u16,
pub st_value: u64,
pub st_size: u64,
}
#[derive(Clone, Debug)]
#[repr(C)]
pub struct ModuleInfo {
pub name: &'static str,
pub version: &'static str,
pub init: fn() -> Result<(), Error>,
pub unload: Option<fn() -> Result<(), Error>>,
}
#[derive(Debug)]
pub struct LoadedModule {
pub image_data: PageBox<[u8]>,
// Ref into the image_data PageBox
pub info: &'static ModuleInfo,
}
pub fn load_kernel_symbol_table<P: AsRef<Path>>(
ioctx: &mut IoContext,
path: P,
) -> Result<(), Error> {
let symbol_file = ioctx.open(None, path, OpenOptions::READ, FileMode::empty())?;
let mut string_buffer = PageBox::new_slice(0, 4096)?;
let mut map = DefaultHashTable::new();
loop {
let mut len = [0; 8];
if symbol_file.read(&mut len)? != len.len() {
break;
}
let len = usize::from_le_bytes(len);
symbol_file.read_exact(&mut string_buffer[..len])?;
let name = core::str::from_utf8(&string_buffer[..len]).unwrap();
let mut value = [0; 8];
symbol_file.read_exact(&mut value)?;
let value = usize::from_le_bytes(value);
map.insert(name.into(), value);
}
KERNEL_SYMBOL_TABLE.init(map);
MODULE_SYMBOL_TABLE.init(Mutex::new(DefaultHashTable::new()));
Ok(())
}
pub fn lookup_symbol(name: &str) -> Option<usize> {
let symtab = KERNEL_SYMBOL_TABLE.get();
if let Some(addr) = symtab.get(name).copied() {
return Some(addr);
}
let symtab = MODULE_SYMBOL_TABLE.get();
if let Some(addr) = symtab.lock().unwrap().get(name).copied() {
return Some(addr);
}
None
}
pub fn load(file: FileRef) -> Result<LoadedModule, Error> {
// TODO better dependency tracking than just throwing undefined references
let (mut elf, mut file) = binary::elf::open_elf_direct(file)?;
// Find out image size
let (vaddr_min, vaddr_max) = binary::elf::elf_virtual_range(&elf);
let mut image_data = PageBox::new_slice(0u8, vaddr_max - vaddr_min)?;
// Load the segments
for segment in elf
.segments()
.iter()
.filter_map(ElfSegment::from_phdr)
.filter(|seg| seg.ty == ElfSegmentType::Load)
{
let rel_offset = segment.vaddr as usize - vaddr_min;
let segment_data = &mut image_data[rel_offset..rel_offset + segment.full_size as usize];
if segment.data_size > 0 {
file.seek(SeekFrom::Start(segment.offset)).unwrap();
file.read_exact(&mut segment_data[..segment.data_size as usize])
.unwrap();
}
}
let mut info_struct_addr = None;
// Extract dynamic symbols
let (dynsym, dynstr) = elf.dynamic_symbol_table().unwrap().unwrap();
let mut dynamic_symbols = vec![];
for mut sym in dynsym {
let name = dynstr.get(sym.st_name as _).unwrap();
if sym.st_shndx == elf::abi::SHN_UNDEF && sym.st_bind() != elf::abi::STB_LOCAL {
let Some(value) = lookup_symbol(&name) else {
log::warn!("Could not load module: undefined reference to {:?} (possibly compiled against a different libk?)", name);
return Err(Error::InvalidArgument);
};
sym.st_value = value as u64;
dynamic_symbols.push(sym);
} else {
// Adjust symbol value by image base
sym.st_value += image_data.as_ptr().addr() as u64;
if name == "MODULE" && sym.st_symtype() == elf::abi::STT_OBJECT {
if sym.st_size != size_of::<ModuleInfo>() as u64 {
todo!();
}
info_struct_addr = Some(sym.st_value as usize);
}
dynamic_symbols.push(sym);
}
}
// Apply relocations
let rela_sections: Vec<_> = elf
.section_headers()
.iter()
.filter(|c| c.sh_type == elf::abi::SHT_RELA)
.copied()
.collect();
for rela in rela_sections {
let rela = elf.section_data_as_relas(&rela).unwrap();
for rela in rela {
let value = match rela.r_type {
// Symbol + addend
elf::abi::R_X86_64_64 => {
if let Some(sym) = dynamic_symbols.get(rela.r_sym as usize) {
sym.st_value as i64 + rela.r_addend
} else {
return Err(Error::InvalidArgument);
}
}
// Image base + addend
elf::abi::R_X86_64_RELATIVE => image_data.as_ptr().addr() as i64 + rela.r_addend,
// Symbol value
elf::abi::R_X86_64_JUMP_SLOT | elf::abi::R_X86_64_GLOB_DAT => {
if let Some(sym) = dynamic_symbols.get(rela.r_sym as usize) {
sym.st_value as i64
} else {
return Err(Error::InvalidArgument);
}
}
_ => todo!("Unhandled relocation: {}", rela.r_type),
};
image_data[rela.r_offset as usize..rela.r_offset as usize + 8]
.copy_from_slice(&value.to_ne_bytes());
}
}
// TODO Add module symbols to export list: make sure to only export properly namespaced items
// let module_syms = MODULE_SYMBOL_TABLE.get();
// for (name, sym) in dynamic_symbols.iter() {
// if sym.st_shndx == elf::abi::SHN_UNDEF || sym.st_vis() != elf::abi::STV_DEFAULT {
// continue;
// }
// if !name.starts_with("_ZN") {
// continue;
// }
// log::info!("Export {:?} -> {:#x}", name, sym.st_value);
// module_syms
// .lock()
// .unwrap()
// .insert(name.clone(), sym.st_value as usize);
// }
let info = info_struct_addr
.map(|addr| unsafe { core::mem::transmute(addr) })
.expect("TODO return error if module is missing MODULE info struct");
Ok(LoadedModule { image_data, info })
}
pub fn load_and_execute(file: FileRef) -> Result<(), Error> {
let module = load(file)?;
(module.info.init)()
}
// TODO roll own hashmap
static KERNEL_SYMBOL_TABLE: OneTimeInit<DefaultHashTable<String, usize, 128>> = OneTimeInit::new();
static MODULE_SYMBOL_TABLE: OneTimeInit<Mutex<DefaultHashTable<String, usize>>> =
OneTimeInit::new();

26
kernel/libk/src/panic.rs Normal file
View File

@ -0,0 +1,26 @@
use core::panic::PanicInfo;
use kernel_arch::{Architecture, ArchitectureImpl};
use libk_util::OneTimeInit;
static PANIC_HANDLER: OneTimeInit<fn(&PanicInfo) -> !> = OneTimeInit::new();
pub fn set_handler(handler: fn(&PanicInfo) -> !) {
PANIC_HANDLER.init(handler);
}
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
if let Some(ph) = PANIC_HANDLER.try_get() {
ph(pi);
} else {
log::error!("{:#?}", pi);
loop {
unsafe {
ArchitectureImpl::set_interrupt_mask(true);
}
ArchitectureImpl::wait_for_interrupt();
}
}
}

View File

@ -34,7 +34,7 @@ pub struct FileReader<F: Read + Seek> {
}
#[derive(Debug, PartialEq)]
enum ElfSegmentType {
pub enum ElfSegmentType {
Load,
Dynamic,
Tls,
@ -45,7 +45,7 @@ pub enum ElfKind<F: Read + Seek> {
Static(ElfStream<AnyEndian, FileReader<Arc<F>>>, FileReader<Arc<F>>),
}
struct ElfSegment {
pub struct ElfSegment {
pub ty: ElfSegmentType,
pub attrs: MapAttributes,
pub offset: u64,
@ -68,7 +68,7 @@ impl<F: Read + Seek> elf::io_traits::InputStream for FileReader<F> {
}
impl ElfSegmentType {
fn from_phdr(phdr: &ProgramHeader) -> Option<Self> {
pub fn from_phdr(phdr: &ProgramHeader) -> Option<Self> {
match phdr.p_type {
elf::abi::PT_LOAD => Some(Self::Load),
elf::abi::PT_DYNAMIC => Some(Self::Dynamic),
@ -79,7 +79,7 @@ impl ElfSegmentType {
}
impl ElfSegment {
fn from_phdr(phdr: &ProgramHeader) -> Option<Self> {
pub fn from_phdr(phdr: &ProgramHeader) -> Option<Self> {
let ty = ElfSegmentType::from_phdr(phdr)?;
let attrs = match (phdr.p_flags & elf::abi::PF_W, phdr.p_flags & elf::abi::PF_X) {
@ -122,8 +122,21 @@ impl ElfSegment {
}
pub fn open_elf_file<F: Read + Seek>(file: Arc<F>) -> Result<ElfKind<F>, Error> {
let (mut elf, file) = open_elf_direct(file)?;
if is_dynamic(&mut elf)? {
// TODO populate interp value
Ok(ElfKind::Dynamic(None))
} else {
Ok(ElfKind::Static(elf, file))
}
}
pub fn open_elf_direct<F: Read + Seek>(
file: Arc<F>,
) -> Result<(ElfStream<AnyEndian, FileReader<Arc<F>>>, FileReader<Arc<F>>), Error> {
let file = FileReader { file };
let mut elf = ElfStream::<AnyEndian, _>::open_stream(file.clone()).map_err(from_parse_error)?;
let elf = ElfStream::<AnyEndian, _>::open_stream(file.clone()).map_err(from_parse_error)?;
if elf.ehdr.e_machine != EXPECTED_ELF_MACHINE {
log::warn!("e_machine in ELF ({:#x}) does not match expected value for current architecture ({:#x})", elf.ehdr.e_machine, EXPECTED_ELF_MACHINE);
@ -141,12 +154,7 @@ pub fn open_elf_file<F: Read + Seek>(file: Arc<F>) -> Result<ElfKind<F>, Error>
return Err(Error::UnrecognizedExecutable);
}
if is_dynamic(&mut elf)? {
// TODO populate interp value
Ok(ElfKind::Dynamic(None))
} else {
Ok(ElfKind::Static(elf, file))
}
Ok((elf, file))
}
/// Loads an ELF binary from `file` into the target address space
@ -255,7 +263,9 @@ fn is_dynamic<F: Read + Seek>(
Ok(dynamic.into_iter().any(|e| e.d_tag == elf::abi::DT_NEEDED))
}
fn elf_virtual_range<F: Read + Seek>(elf: &ElfStream<AnyEndian, FileReader<F>>) -> (usize, usize) {
pub fn elf_virtual_range<F: Read + Seek>(
elf: &ElfStream<AnyEndian, FileReader<F>>,
) -> (usize, usize) {
let mut vaddr_min = usize::MAX;
let mut vaddr_max = usize::MIN;

1
kernel/modules/test_mod/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

575
kernel/modules/test_mod/Cargo.lock generated Normal file
View File

@ -0,0 +1,575 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aarch64-cpu"
version = "9.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287"
dependencies = [
"tock-registers",
]
[[package]]
name = "abi-generator"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
"thiserror",
]
[[package]]
name = "abi-lib"
version = "0.1.0"
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
name = "atomic_enum"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6227a8d6fdb862bcb100c4314d0d9579e5cd73fa6df31a2e6f6e1acd3c5f1207"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "btree_monstrousity"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4d0977e9c15f276380f16f2e9594257c258172b23af39ffd2e4cf5971cb38c7"
dependencies = [
"cfg-if",
"rustversion",
]
[[package]]
name = "bytemuck"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-queue"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
[[package]]
name = "device-api"
version = "0.1.0"
dependencies = [
"device-api-macros",
"yggdrasil-abi",
]
[[package]]
name = "device-api-macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "discrete_range_map"
version = "0.6.2"
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#10fd79828d2918bd079a11c2b2c623eede170c3f"
dependencies = [
"btree_monstrousity",
"either",
"itertools",
"serde",
]
[[package]]
name = "either"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "elf"
version = "0.7.2"
source = "git+https://git.alnyan.me/yggdrasil/yggdrasil-elf.git#419cd311de2e9514b5033677cde9a33f7d0ba4a2"
dependencies = [
"hashbrown",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "kernel-arch"
version = "0.1.0"
dependencies = [
"cfg-if",
"kernel-arch-aarch64",
"kernel-arch-hosted",
"kernel-arch-interface",
"kernel-arch-x86_64",
]
[[package]]
name = "kernel-arch-aarch64"
version = "0.1.0"
dependencies = [
"aarch64-cpu",
"bitflags",
"device-api",
"kernel-arch-interface",
"libk-mm-interface",
"memtables",
"static_assertions",
"tock-registers",
"yggdrasil-abi",
]
[[package]]
name = "kernel-arch-hosted"
version = "0.1.0"
dependencies = [
"kernel-arch-interface",
"libk-mm-interface",
"yggdrasil-abi",
]
[[package]]
name = "kernel-arch-interface"
version = "0.1.0"
dependencies = [
"device-api",
"yggdrasil-abi",
]
[[package]]
name = "kernel-arch-x86_64"
version = "0.1.0"
dependencies = [
"bitflags",
"device-api",
"kernel-arch-interface",
"libk-mm-interface",
"memtables",
"static_assertions",
"tock-registers",
"yggdrasil-abi",
]
[[package]]
name = "libk"
version = "0.1.0"
dependencies = [
"abi-lib",
"atomic_enum",
"bytemuck",
"cfg-if",
"crossbeam-queue",
"device-api",
"elf",
"futures-util",
"kernel-arch",
"libk-device",
"libk-mm",
"libk-util",
"log",
"serde",
"serde_json",
"yggdrasil-abi",
]
[[package]]
name = "libk-device"
version = "0.1.0"
dependencies = [
"device-api",
"kernel-arch",
"libk-util",
"yggdrasil-abi",
]
[[package]]
name = "libk-mm"
version = "0.1.0"
dependencies = [
"kernel-arch",
"libk-mm-interface",
"libk-util",
"linked_list_allocator",
"log",
"vmalloc",
"yggdrasil-abi",
]
[[package]]
name = "libk-mm-interface"
version = "0.1.0"
dependencies = [
"bitflags",
"bytemuck",
"kernel-arch-interface",
"yggdrasil-abi",
]
[[package]]
name = "libk-util"
version = "0.1.0"
dependencies = [
"ahash",
"crossbeam-queue",
"futures-util",
"kernel-arch",
"log",
"yggdrasil-abi",
]
[[package]]
name = "linked_list_allocator"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
dependencies = [
"spinning_top",
]
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "memtables"
version = "0.1.0"
dependencies = [
"bytemuck",
]
[[package]]
name = "module-build"
version = "0.1.0"
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "pin-project-lite"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "prettyplease"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
dependencies = [
"proc-macro2",
"syn 2.0.53",
]
[[package]]
name = "proc-macro2"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "serde_json"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "spinning_top"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
dependencies = [
"lock_api",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "test_mod"
version = "0.1.0"
dependencies = [
"libk",
"module-build",
]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]
[[package]]
name = "tock-registers"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vmalloc"
version = "0.1.0"
dependencies = [
"discrete_range_map",
"yggdrasil-abi",
]
[[package]]
name = "yggdrasil-abi"
version = "0.1.0"
dependencies = [
"abi-generator",
"abi-lib",
"prettyplease",
"serde",
]
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.53",
]

View File

@ -0,0 +1,18 @@
[package]
name = "test_mod"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["dylib"]
[dependencies]
# FIXME: this makes rust-analyzer work properly
[dev-dependencies]
libk = { path = "../../libk" }
[build-dependencies]
module-build = { path = "../../lib/module-build" }
[workspace]

View File

@ -0,0 +1,3 @@
fn main() {
module_build::build();
}

View File

@ -0,0 +1,2 @@
name = "test_mod"
version = "0.0.1"

View File

@ -0,0 +1,30 @@
#![no_std]
#![no_main]
use core::time::Duration;
use libk::{error::Error, log, module::ModuleInfo, task::runtime};
#[no_mangle]
static MODULE: ModuleInfo = ModuleInfo {
// TODO generate this from manifest toml
name: "test_mod",
version: "0.0.1",
init,
unload: Some(unload),
};
fn init() -> Result<(), Error> {
log::info!("Module loaded");
runtime::spawn(async move {
loop {
log::debug!("Tick");
runtime::sleep(Duration::from_secs(1)).await;
}
})
}
fn unload() -> Result<(), Error> {
log::info!("Module unloaded");
Ok(())
}

View File

@ -19,6 +19,7 @@ use kernel_arch_x86_64::CPU_COUNT;
use libk::device::external_interrupt_controller;
use libk_mm::{
address::{FromRaw, PhysicalAddress, Virtualize},
heap::GLOBAL_HEAP,
pointer::PhysicalRef,
};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
@ -29,7 +30,7 @@ use crate::{
x86_64::{apic::ioapic::ISA_IRQ_OFFSET, SHUTDOWN_FENCE},
Platform, PLATFORM,
},
mem::{heap::GLOBAL_HEAP, read_memory, write_memory},
mem::{read_memory, write_memory},
};
use super::intrinsics;

View File

@ -19,6 +19,7 @@ use libk::{arch::Cpu, device::register_external_interrupt_controller};
use libk_device::register_monotonic_timestamp_provider;
use libk_mm::{
address::{FromRaw, IntoRaw, PhysicalAddress, Virtualize},
heap,
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
table::{EntryLevel, EntryLevelExt},
};
@ -48,7 +49,6 @@ use crate::{
display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
},
fs::{Initrd, INITRD_DATA},
mem::heap,
};
use self::{

View File

@ -4,6 +4,7 @@ use abi::error::Error;
use alloc::borrow::ToOwned;
use kernel_fs::devfs;
use libk::{
module::load_kernel_symbol_table,
random,
task::{process::Process, runtime, thread::Thread},
vfs::{impls::fn_symlink, IoContext, NodeRef},
@ -67,6 +68,9 @@ pub fn kinit() -> Result<(), Error> {
let mut ioctx = IoContext::new(root);
// TODO maybe better to load this from userspace or along with the kernel
load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?;
{
let group_id = Process::create_group();
let (user_init, user_init_main) =

View File

@ -41,9 +41,10 @@
use arch::Platform;
use kernel_arch::{Architecture, ArchitectureImpl};
use libk::arch::Cpu;
use libk_mm::heap;
use libk_util::sync::SpinFence;
use crate::{arch::PLATFORM, fs::sysfs, mem::heap, task::spawn_kernel_closure};
use crate::{arch::PLATFORM, fs::sysfs, task::spawn_kernel_closure};
extern crate yggdrasil_abi as abi;
@ -90,6 +91,8 @@ pub fn kernel_secondary_main() -> ! {
/// * Basic debugging facilities
/// * Initrd
pub fn kernel_main() -> ! {
libk::panic::set_handler(panic::panic_handler);
debugln!("Heap: {:#x?}", heap::heap_range());
// Setup the sysfs

View File

@ -1,66 +0,0 @@
//! Kernel's global heap allocator
use core::{
alloc::{GlobalAlloc, Layout},
ops::Range,
ptr::{null_mut, NonNull},
};
use libk_util::sync::IrqSafeSpinlock;
use linked_list_allocator::Heap;
/// Kernel heap manager
pub struct KernelAllocator {
inner: IrqSafeSpinlock<Heap>,
}
impl KernelAllocator {
const fn empty() -> Self {
Self {
inner: IrqSafeSpinlock::new(Heap::empty()),
}
}
unsafe fn init(&self, base: usize, size: usize) {
self.inner.lock().init(base as _, size);
}
fn range(&self) -> Range<usize> {
let lock = self.inner.lock();
lock.bottom() as usize..lock.top() as usize
}
}
unsafe impl GlobalAlloc for KernelAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
match self.inner.lock().allocate_first_fit(layout) {
Ok(v) => v.as_ptr(),
Err(e) => {
errorln!("Failed to allocate {:?}: {:?}", layout, e);
null_mut()
}
}
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let ptr = NonNull::new(ptr).unwrap();
self.inner.lock().deallocate(ptr, layout)
}
}
/// Kernel's global allocator
#[global_allocator]
pub static GLOBAL_HEAP: KernelAllocator = KernelAllocator::empty();
/// Sets up kernel's global heap with given memory range.
///
/// # Safety
///
/// The caller must ensure the range is valid and mapped virtual memory.
pub unsafe fn init_heap(heap_base: usize, heap_size: usize) {
GLOBAL_HEAP.init(heap_base, heap_size);
}
/// Returns the heap address range
pub fn heap_range() -> Range<usize> {
GLOBAL_HEAP.range()
}

View File

@ -9,8 +9,6 @@ use libk_mm::{address::PhysicalAddress, device::DeviceMemoryMapping};
use crate::arch::{Platform, PlatformImpl};
pub mod heap;
/// Offset applied to the physical kernel image when translating it into the virtual address space
pub const KERNEL_VIRT_OFFSET: usize = PlatformImpl::KERNEL_VIRT_OFFSET;

View File

@ -40,14 +40,11 @@ pub fn panic_secondary() -> ! {
}
}
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
pub(crate) fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
let cpu = Cpu::local();
static PANIC_HAPPENED: AtomicBool = AtomicBool::new(false);
fatalln!("{:?}", pi);
if PANIC_HAPPENED
.compare_exchange(false, true, Ordering::Release, Ordering::Acquire)
.is_ok()

View File

@ -1,4 +1,3 @@
use abi::process::{ExecveOptions, ProcessId};
pub(crate) use abi::{
error::Error,
io::{
@ -10,7 +9,11 @@ pub(crate) use abi::{
process::{Signal, SignalEntryData, SpawnOptions},
system::SystemInfo,
};
use libk::{random, task::thread::Thread};
use abi::{
path::Path,
process::{ExecveOptions, ProcessId},
};
use libk::{module, random, task::thread::Thread};
use libk_mm::phys;
use crate::fs;
@ -56,6 +59,21 @@ pub(crate) fn get_system_info(element: &mut SystemInfo) -> Result<(), Error> {
}
}
pub(crate) fn load_module(path: &str) -> Result<(), Error> {
let thread = Thread::current();
let process = thread.process();
let file = run_with_io(&process, |mut io| {
let path: &Path = path.as_ref();
if !path.is_absolute() {
todo!();
}
io.ioctx_mut().open_executable(path)
})?;
module::load_and_execute(file)
}
// Handled outside
pub(crate) fn exit_signal(_frame: &SignalEntryData) -> ! {
unreachable!()

View File

@ -1,5 +1,6 @@
use core::fmt;
use std::{
collections::HashMap,
io::{Read, Seek},
mem::offset_of,
};
@ -12,7 +13,7 @@ use elf::{
};
use memtables::aarch64::{FixedTables, KERNEL_L3_COUNT};
use crate::{GenData, GenError};
use crate::{extract_symbols, GenData, GenError};
bitflags! {
#[derive(Clone, Copy)]
@ -105,7 +106,7 @@ impl<F: Read + Seek> AArch64Builder<F> {
// TODO the build function is almost identical to x86-64 one, but with slight changes, so might
// wanna unify this later
pub fn build(mut self) -> Result<(FixedTables, u64), GenError> {
pub fn build(mut self) -> Result<(FixedTables, u64, HashMap<String, usize>), GenError> {
assert_eq!(offset_of!(FixedTables, l1), 0);
let l2_physical_address =
@ -123,6 +124,8 @@ impl<F: Read + Seek> AArch64Builder<F> {
self.tables.l2.data[l2i] = l3_physical_address | PageFlags::kernel_table().bits();
}
let symbol_table = extract_symbols(&mut self.elf)?;
for (i, segment) in self.elf.segments().into_iter().enumerate() {
if segment.p_type != PT_LOAD
|| segment.p_vaddr != segment.p_paddr + self.data.kernel_virt_offset
@ -155,7 +158,7 @@ impl<F: Read + Seek> AArch64Builder<F> {
)?;
}
Ok((self.tables, self.data.table_offset))
Ok((self.tables, self.data.table_offset, symbol_table))
}
fn map_segment(

View File

@ -1,5 +1,6 @@
use std::{
fs::OpenOptions,
collections::{HashMap, HashSet},
fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom, Write},
ops::Range,
path::{Path, PathBuf},
@ -37,6 +38,8 @@ pub enum GenError {
MissingSymbol(&'static str),
#[error("Kernel image is missing a required section: {0:?}")]
MissingSection(&'static str),
#[error("Kernel image is missing a symbol table")]
MissingSymbolTable,
#[error("Incorrect tables section placement: {0:#x}")]
IncorrectTablesPlacement(u64),
}
@ -44,6 +47,7 @@ pub enum GenError {
#[derive(Parser)]
struct Args {
image: PathBuf,
symbol_out: PathBuf,
}
pub struct GenData {
@ -119,11 +123,61 @@ fn find_tables<F: Read + Seek>(elf: &mut ElfStream<AnyEndian, F>) -> Result<(u64
Err(GenError::MissingSection(".data.tables"))
}
fn into_any<T: Into<AnyTables>, U>((l, r): (T, U)) -> (AnyTables, U) {
(l.into(), r)
fn extract_symbols<F: Read + Seek>(
elf: &mut ElfStream<AnyEndian, F>,
) -> Result<HashMap<String, usize>, GenError> {
let mut table = HashMap::new();
// let mut export_tables = HashSet::new();
// let force_export = &[
// "rust_begin_unwind",
// "__rust_alloc",
// "__rust_alloc_zeroed",
// "__rust_dealloc",
// "__rust_realloc",
// ];
// // Find all .export table indices
// let (shdrs, strtab) = elf.section_headers_with_strtab()?;
// let strtab = strtab.ok_or_else(|| GenError::MissingSection(".strtab"))?;
// for (i, shdr) in shdrs.iter().enumerate() {
// if shdr.sh_type != elf::abi::SHT_PROGBITS {
// continue;
// }
// let name = strtab.get(shdr.sh_name as _)?;
// if name.starts_with(".export.") {
// println!("Export from {:?}", name);
// export_tables.insert(i as u16);
// }
// }
let (symtab, strtab) = elf.symbol_table()?.ok_or(GenError::MissingSymbolTable)?;
// Only produce symbols from .export tables
for sym in symtab {
if sym.st_vis() == elf::abi::STV_HIDDEN {
continue;
}
let name = strtab.get(sym.st_name as _)?;
// if export_tables.contains(&sym.st_shndx) || force_export.contains(&name) {
table.insert(name.to_owned(), sym.st_value as usize);
// }
}
println!("{} exported symbols extracted", table.len());
Ok(table)
}
fn build_tables<F: Read + Seek>(file: F) -> Result<(AnyTables, u64), GenError> {
fn into_any<T: Into<AnyTables>, U, V>((x, y, z): (T, U, V)) -> (AnyTables, U, V) {
(x.into(), y, z)
}
fn build_tables<F: Read + Seek>(
file: F,
) -> Result<(AnyTables, u64, HashMap<String, usize>), GenError> {
let mut elf = ElfStream::<AnyEndian, F>::open_stream(file)?;
let kernel_virt_offset = kernel_virt_offset(&mut elf)?;
@ -175,14 +229,30 @@ fn write_tables<F: Write + Seek>(
Ok(())
}
fn gentables<P: AsRef<Path>>(image: P) -> Result<(), GenError> {
fn write_symbol_table(
out: impl AsRef<Path>,
table: HashMap<String, usize>,
) -> Result<(), GenError> {
let mut file = File::create(out)?;
for (name, value) in table {
file.write_all(&name.len().to_le_bytes())?;
file.write_all(name.as_bytes())?;
file.write_all(&value.to_le_bytes())?;
}
Ok(())
}
fn gentables(image: impl AsRef<Path>, symbol_out: impl AsRef<Path>) -> Result<(), GenError> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.truncate(false)
.open(image)?;
let (tables, file_offset) = build_tables(&mut file)?;
let (tables, file_offset, symbol_table) = build_tables(&mut file)?;
write_symbol_table(symbol_out, symbol_table)?;
write_tables(file, file_offset, tables)?;
Ok(())
@ -191,7 +261,7 @@ fn gentables<P: AsRef<Path>>(image: P) -> Result<(), GenError> {
fn main() -> ExitCode {
let args = Args::parse();
match gentables(&args.image) {
match gentables(&args.image, &args.symbol_out) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("{}: {}", args.image.display(), err);

View File

@ -1,5 +1,6 @@
use core::fmt;
use std::{
collections::HashMap,
io::{Read, Seek},
mem::offset_of,
};
@ -8,7 +9,7 @@ use bitflags::bitflags;
use elf::{abi::PT_LOAD, endian::AnyEndian, ElfStream};
use memtables::x86_64::{FixedTables, KERNEL_L3_COUNT};
use crate::{GenData, GenError};
use crate::{extract_symbols, GenData, GenError};
bitflags! {
#[derive(Clone, Copy)]
@ -92,7 +93,7 @@ impl<F: Seek + Read> X8664Builder<F> {
})
}
pub fn build(mut self) -> Result<(FixedTables, u64), GenError> {
pub fn build(mut self) -> Result<(FixedTables, u64, HashMap<String, usize>), GenError> {
assert_eq!(offset_of!(FixedTables, l0), 0);
let l1_physical_address =
self.data.table_physical_address + offset_of!(FixedTables, kernel_l1) as u64;
@ -117,6 +118,9 @@ impl<F: Seek + Read> X8664Builder<F> {
l3_physical_address | (PageFlags::PRESENT | PageFlags::WRITABLE).bits();
}
// Locate symbol table
let symbol_table = extract_symbols(&mut self.elf)?;
for (i, segment) in self.elf.segments().into_iter().enumerate() {
if segment.p_type != PT_LOAD
|| segment.p_vaddr != segment.p_paddr + self.data.kernel_virt_offset
@ -149,7 +153,7 @@ impl<F: Seek + Read> X8664Builder<F> {
)?;
}
Ok((self.tables, self.data.table_offset))
Ok((self.tables, self.data.table_offset, symbol_table))
}
fn map_segment(

View File

@ -48,6 +48,7 @@ syscall get_random(buffer: &mut [u8]);
syscall get_system_info(info: &mut SystemInfo) -> Result<()>;
syscall mount(opts: &MountOptions<'_>) -> Result<()>;
syscall unmount(opts: &UnmountOptions) -> Result<()>;
syscall load_module(path: &str) -> Result<()>;
// Memory management
syscall map_memory(hint: Option<NonZeroUsize>, len: usize, source: &MappingSource) -> Result<usize>;

1
userspace/Cargo.lock generated
View File

@ -929,6 +929,7 @@ dependencies = [
"sha2",
"thiserror",
"yggdrasil-abi",
"yggdrasil-rt",
]
[[package]]

View File

@ -15,4 +15,4 @@ members = [
"dyn-loader",
"rdb"
]
exclude = ["dynload-program"]
exclude = ["dynload-program", "test-kernel-module"]

View File

@ -9,6 +9,7 @@ authors = ["Mark Poliakov <mark@alnyan.me>"]
[dependencies]
libterm = { path = "../lib/libterm" }
yggdrasil-abi = { path = "../../lib/abi", features = ["serde", "alloc", "bytemuck"] }
yggdrasil-rt = { path = "../../lib/runtime" }
thiserror = "1.0.50"
clap = { version = "4.3.19", features = ["std", "derive", "help", "usage"], default-features = false }
@ -41,6 +42,10 @@ path = "src/service.rs"
name = "logd"
path = "src/logd.rs"
[[bin]]
name = "kmod"
path = "src/kmod.rs"
# /bin
[[bin]]
name = "ls"

View File

@ -0,0 +1,13 @@
use clap::Parser;
#[derive(Parser)]
pub struct Args {
path: String,
}
fn main() {
let args = Args::parse();
unsafe {
yggdrasil_rt::sys::load_module(&args.path).unwrap();
}
}

View File

@ -17,3 +17,5 @@ walkdir = "2.5.0"
tar = "0.4.40"
env_logger = "0.11.2"
log = "0.4.21"
dependency-graph = "0.1.5"
semver = { version = "1.0.22", features = ["serde"] }

View File

@ -1,14 +1,44 @@
use std::{ffi::OsStr, path::Path, process::Command};
use std::{
collections::HashMap,
ffi::OsStr,
path::{Path, PathBuf},
process::Command,
};
use serde::Deserialize;
use crate::{
env::{BuildEnv, Profile},
error::Error,
};
#[derive(Debug, Clone, Deserialize)]
pub struct ModuleDependency {
pub version: Option<semver::VersionReq>,
pub path: PathBuf,
}
#[derive(Debug, Deserialize)]
pub struct ModuleManifest {
pub name: String,
pub version: semver::Version,
#[serde(default)]
pub dependencies: HashMap<String, ModuleDependency>,
}
#[derive(Debug)]
pub struct ModuleInfo {
pub dependencies: Vec<(String, String, ModuleDependency)>,
pub module_dir_name: PathBuf,
pub manifest_dir: PathBuf,
pub manifest: ModuleManifest,
}
pub enum CargoBuilder<'e> {
Host(bool),
Userspace(&'e BuildEnv),
Kernel(&'e BuildEnv),
Module(&'e BuildEnv, &'e ModuleInfo),
}
impl<'e> CargoBuilder<'e> {
@ -56,6 +86,14 @@ impl<'e> CargoBuilder<'e> {
}
}
Self::Kernel(env) => {
command.env(
"RUSTFLAGS",
format!(
"-C link-arg=-T{}/etc/{}.ld",
env.workspace_root.display(),
env.arch.kernel_triple()
),
);
command.arg("+nightly").arg(arg);
if env.verbose {
@ -71,6 +109,72 @@ impl<'e> CargoBuilder<'e> {
command.arg(target_spec_arg);
command.args(["-Z", "build-std=core,alloc,compiler_builtins"]);
if env.profile == Profile::Release {
command.arg("--release");
}
}
Self::Module(env, module) => {
let mut lib_paths = vec![];
let mut extern_libs = vec![];
let mut dependency_list = String::new();
for (i, (name, dep)) in module.manifest.dependencies.iter().enumerate() {
if i != 0 {
dependency_list.push(':');
}
let dep_path = module.manifest_dir.join(&dep.path).canonicalize()?;
let output_dir = dep_path.join(format!(
"target/{}/{}",
env.arch.kernel_triple(),
env.profile.name()
));
let dependency_so = output_dir.join(format!("lib{}.so", name));
lib_paths.push(output_dir.join("deps"));
lib_paths.push(output_dir.clone());
lib_paths.push(dep_path.join(format!("target/{}/deps", env.profile.name())));
dependency_list.push_str(&format!("{}={}", name, dependency_so.display()));
extern_libs.push((name.clone(), dependency_so));
}
lib_paths.push(env.kernel_output_dir.join("deps"));
lib_paths.push(env.kernel_output_dir.clone());
lib_paths.push(
env.workspace_root
.join(format!("target/{}/deps", env.profile.name())),
);
extern_libs.push(("libk".into(), env.kernel_output_dir.join("liblibk.so")));
let mut rust_flags = Vec::new();
for lib_path in lib_paths {
rust_flags.push(format!("-L{}", lib_path.display()));
}
for (lib, path) in extern_libs {
rust_flags.push(format!("--extern {}={}", lib, path.display()));
}
rust_flags.push("-Cprefer-dynamic".into());
command.env("RUSTFLAGS", rust_flags.join(" "));
command.env("MOD_DEPENDENCIES", dependency_list);
command.env("MOD_LIBK_SO", env.kernel_output_dir.join("liblibk.so"));
command.arg("+nightly").arg(arg);
if env.verbose {
command.arg("-v");
}
let target_spec_arg = format!(
"--target={}/etc/{}.json",
env.workspace_root.display(),
env.arch.kernel_triple()
);
command.arg(target_spec_arg);
if env.profile == Profile::Release {
command.arg("--release");
}

View File

@ -1,7 +1,10 @@
use std::{path::PathBuf, process::Command};
use std::{
path::{Path, PathBuf},
process::Command,
};
use crate::{
build::cargo::CargoBuilder,
build::{cargo::CargoBuilder, module::build_modules},
check::{self, AllOk},
env::{Arch, BuildEnv},
error::Error,
@ -10,6 +13,7 @@ use crate::{
pub mod x86_64;
mod cargo;
mod module;
pub mod toolchain;
mod userspace;
@ -53,11 +57,15 @@ pub fn build_kernel(env: &BuildEnv, _: AllOk) -> Result<KernelBuilt, Error> {
}
pub fn generate_kernel_tables(
symbol_path: impl AsRef<Path>,
kernel: KernelBuilt,
tools: ToolsBuilt,
) -> Result<KernelProcessed, Error> {
log::info!("Generating kernel MMU translation tables");
let status = Command::new(tools.0).arg(kernel.0.clone()).status()?;
let status = Command::new(tools.0)
.arg(kernel.0.clone())
.arg(symbol_path.as_ref())
.status()?;
if status.success() {
Ok(KernelProcessed(kernel))
} else {
@ -73,10 +81,16 @@ pub fn build_all(env: BuildEnv) -> Result<AllBuilt, Error> {
// Kernel stuff
let tools = build_kernel_tools(&env, check)?;
let kernel = build_kernel(&env, check)?;
let kernel = generate_kernel_tables(kernel, tools)?;
let kernel = generate_kernel_tables(&env.kernel_symbol_file, kernel, tools)?;
let modules = build_modules(&env, env.workspace_root.join("kernel/modules"))?;
let mut install_extra = vec![];
for module in modules {
install_extra.push((module.clone(), module.file_name().unwrap().into()));
}
// Userspace stuff
let initrd = userspace::build_initrd(&env, check)?;
let initrd = userspace::build_initrd(&env, install_extra, check)?;
// Build target-specific image
let image = match env.arch {

112
xtask/src/build/module.rs Normal file
View File

@ -0,0 +1,112 @@
use std::{
fs::{self, FileType},
path::{Path, PathBuf},
};
use dependency_graph::{DependencyGraph, Node, Step};
use crate::{
build::cargo::{CargoBuilder, ModuleManifest},
env::BuildEnv,
error::Error,
};
use super::cargo::{ModuleDependency, ModuleInfo};
pub fn build_module(env: &BuildEnv, info: &ModuleInfo) -> Result<PathBuf, Error> {
log::info!("Building module: {:?}", info.manifest.name);
CargoBuilder::Module(env, info).build(&info.manifest_dir)?;
Ok(info.manifest_dir.join(format!(
"target/{}/{}/lib{}.so",
env.arch.kernel_triple(),
env.profile.name(),
info.module_dir_name.display()
)))
}
impl Node for ModuleInfo {
type DependencyType = (String, String, ModuleDependency);
fn matches(&self, dependency: &Self::DependencyType) -> bool {
let (_, dep_name, dep_info) = dependency;
let version_match = dep_info
.version
.as_ref()
.map(|v| v.matches(&self.manifest.version))
.unwrap_or(true);
let name_match = dep_name == &self.manifest.name;
name_match && version_match
}
fn dependencies(&self) -> &[Self::DependencyType] {
&self.dependencies
}
}
pub fn collect_module_list<P: AsRef<Path>>(dir: P) -> Result<Vec<ModuleInfo>, Error> {
let mut module_list = vec![];
for dir in fs::read_dir(dir)? {
let dir = dir?;
let manifest = dir.path().join("module.toml");
if !dir
.file_type()
.as_ref()
.map(FileType::is_dir)
.unwrap_or(false)
|| !manifest.exists()
{
continue;
}
let manifest: ModuleManifest = toml::from_str(&fs::read_to_string(&manifest)?)
.map_err(|e| Error::TomlParseError(manifest, e))?;
module_list.push(ModuleInfo {
module_dir_name: dir.file_name().to_str().unwrap().into(),
dependencies: manifest
.dependencies
.iter()
.map(|(k, v)| (manifest.name.clone(), k.clone(), v.clone()))
.collect(),
manifest,
manifest_dir: dir.path(),
});
}
Ok(module_list)
}
pub fn build_modules<P: AsRef<Path>>(env: &BuildEnv, dir: P) -> Result<Vec<PathBuf>, Error> {
let modules = collect_module_list(dir)?;
let graph = DependencyGraph::from(&modules[..]);
let mut any_unresolved = false;
let mut build_steps = vec![];
for entry in graph {
match entry {
Step::Unresolved((name, dep_name, dep)) => {
log::error!("{:?}: unresolved dependency: {:?}", name, dep_name);
if let Some(version) = dep.version.as_ref() {
log::error!("\tCould not satisfy required version: {}", version);
}
any_unresolved = true;
}
Step::Resolved(package) => {
build_steps.push(package);
}
}
}
if any_unresolved {
return Err(Error::UnresolvedModuleDependencies);
}
let built = build_steps
.into_iter()
.map(|entry| build_module(env, entry))
.collect::<Result<Vec<_>, _>>()?;
Ok(built)
}

View File

@ -1,7 +1,7 @@
use std::{
fs::{self, File},
io::BufWriter,
path::Path,
path::{Path, PathBuf},
};
use walkdir::WalkDir;
@ -16,6 +16,7 @@ const PROGRAMS: &[(&str, &str)] = &[
("rc", "sbin/rc"),
("service", "sbin/service"),
("logd", "sbin/logd"),
("kmod", "sbin/kmod"),
// shell
("shell", "bin/sh"),
// sysutils
@ -59,6 +60,7 @@ fn build_userspace(env: &BuildEnv, _: AllOk) -> Result<(), Error> {
fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
env: &BuildEnv,
install_extra: Vec<(PathBuf, PathBuf)>,
build_dir: S,
rootfs_dir: D,
_: AllOk,
@ -106,6 +108,13 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
env.arch.name()
), rootfs_dir.join("lib/libstd.so"))?;
log::info!("Installing extras");
for (src, dst) in install_extra {
util::copy_file(src, rootfs_dir.join(dst))?;
}
util::copy_file(&env.kernel_symbol_file, rootfs_dir.join("kernel.sym"))?;
// Copy /etc
util::copy_dir_recursive(user_dir.join("etc"), rootfs_dir.join("etc"))?;
@ -155,10 +164,20 @@ fn pack_initrd<P: AsRef<Path>>(env: &BuildEnv, rootfs_dir: P) -> Result<InitrdGe
Ok(InitrdGenerated(initrd_tar))
}
pub fn build_initrd(env: &BuildEnv, check: AllOk) -> Result<InitrdGenerated, Error> {
pub fn build_initrd(
env: &BuildEnv,
install_extra: Vec<(PathBuf, PathBuf)>,
check: AllOk,
) -> Result<InitrdGenerated, Error> {
let rootfs_dir = env.userspace_output_dir.join("rootfs");
build_userspace(env, check)?;
build_rootfs(env, &env.userspace_output_dir, &rootfs_dir, check)?;
build_rootfs(
env,
install_extra,
&env.userspace_output_dir,
&rootfs_dir,
check,
)?;
pack_initrd(env, rootfs_dir)
}

View File

@ -43,6 +43,7 @@ pub struct BuildEnv {
pub kernel_output_dir: PathBuf,
pub userspace_output_dir: PathBuf,
pub kernel_symbol_file: PathBuf,
}
impl Default for ToolchainConfig {
@ -68,6 +69,7 @@ impl BuildEnv {
arch.name(),
profile.dir()
));
let kernel_symbol_file = kernel_output_dir.join("symbols.dat");
let host = env!("TARGET");
Self {
@ -80,6 +82,7 @@ impl BuildEnv {
workspace_root,
kernel_symbol_file,
kernel_output_dir,
userspace_output_dir,
}

View File

@ -20,12 +20,14 @@ pub enum Error {
ToolchainBuildFailed,
#[error("Could not configure toolchain: {0}")]
ToolchainConfigError(#[from] toml::ser::Error),
#[error("Could not load qemu.toml: {0}")]
InvalidQemuConfig(#[from] toml::de::Error),
#[error("Could not read {0}: {1}")]
TomlParseError(PathBuf, toml::de::Error),
#[error("Could not copy directory")]
CopyDirectoryError(#[from] walkdir::Error),
#[error("Could not copy file {1:?} -> {2:?}: {0}")]
CopyFileError(io::Error, PathBuf, PathBuf),
#[error("Invalid path: {0:?}")]
InvalidPath(PathBuf),
#[error("Could not resolve modules")]
UnresolvedModuleDependencies,
}

View File

@ -1,4 +1,4 @@
#![deny(warnings)]
// #![deny(warnings)]
use std::{fs, path::PathBuf, process::ExitCode};
@ -97,7 +97,8 @@ fn run(args: Args) -> Result<(), Error> {
} else {
Profile::Debug
};
let config = toml::from_str(&fs::read_to_string(args.config_path)?)?;
let config = toml::from_str(&fs::read_to_string(&args.config_path)?)
.map_err(|e| Error::TomlParseError(args.config_path.clone(), e))?;
let env = env::BuildEnv::new(config, args.verbose, profile, args.arch, workspace_root);
if args.clean_userspace && !matches!(&action, SubArgs::Clean { .. }) {

View File

@ -63,7 +63,7 @@ impl Default for QemuX86_64MachineConfig {
fn default() -> Self {
Self {
enable_kvm: true,
memory: 512,
memory: 1024,
}
}
}
@ -153,7 +153,8 @@ fn load_qemu_config<P: AsRef<Path>>(path: P) -> Result<QemuConfig, Error> {
if path.exists() {
let config = std::fs::read_to_string(path)?;
let config = toml::from_str(&config).map_err(Error::InvalidQemuConfig)?;
let config =
toml::from_str(&config).map_err(|e| Error::TomlParseError(path.to_owned(), e))?;
Ok(config)
} else {