~demindiro/norost-b

75024f9c159b49808798ca159a92a5cb6d408a92 — David Hoppenbrouwers 5 months ago 64cd7c6
Add git hooks, cargo fmt
M drivers/virtio_block/src/main.rs => drivers/virtio_block/src/main.rs +37 -45
@@ 19,10 19,8 @@ extern "C" fn main() {
	'found_dev: while let Some((i, inf)) = syscall::next_table(id) {
		syslog!("table: {:?} -> {:?}", i, core::str::from_utf8(inf.name()));
		if inf.name() == b"pci" {
			let tags: [syscall::Slice<u8>; 2] = [
				b"vendor-id:1af4".into(),
				b"device-id:1001".into(),
			];
			let tags: [syscall::Slice<u8>; 2] =
				[b"vendor-id:1af4".into(), b"device-id:1001".into()];
			let h = syscall::query_table(i, None, &tags).unwrap();
			syslog!("{:?}", h);
			let mut buf = [0; 256];


@@ 44,14 42,7 @@ extern "C" fn main() {

	syslog!("handle: {:?}", handle);

	let pci = unsafe {
		pci::Pci::new(
			pci_config.cast(),
			0,
			0,
			&[],
		)
	};
	let pci = unsafe { pci::Pci::new(pci_config.cast(), 0, 0, &[]) };

	let mut dma_addr = 0x2666_0000;



@@ 84,7 75,8 @@ extern "C" fn main() {
					let a = syscall::physical_address(d).unwrap();
					Ok((d.cast(), a))
				};
				let d = virtio_block::BlockDevice::new(h, get_phys_addr, map_bar, dma_alloc).unwrap();
				let d =
					virtio_block::BlockDevice::new(h, get_phys_addr, map_bar, dma_alloc).unwrap();

				syslog!("pci status: {:#x}", h.status());



@@ 105,7 97,7 @@ extern "C" fn main() {

	// Register new table of Streaming type
	let tbl = syscall::create_table("virtio-blk", syscall::TableType::Streaming).unwrap();
	

	// Register a new object
	// TODO



@@ 131,39 123,39 @@ extern "C" fn main() {

		// Log events
		//while let Some(cmd) = cmds.pop_command() {
			/*
			{
				syslog!("[stream-table] {:?}", "open");
				Response::open(
					&cmd,
					NonNull::new(wr.get()).unwrap().cast(),
					12,
					NonNull::new(rd.get()).unwrap().cast(),
					12,
				)
		/*
		{
			syslog!("[stream-table] {:?}", "open");
			Response::open(
				&cmd,
				NonNull::new(wr.get()).unwrap().cast(),
				12,
				NonNull::new(rd.get()).unwrap().cast(),
				12,
			)
		}
		{
			syslog!("[stream-table] {:?}", count);

			let wr: &[u8] = unsafe {
				core::slice::from_raw_parts(wr.get().cast(), 4096)
			};
			syslog!("{:#x?}", syscall::physical_address(NonNull::from(wr).cast()));
			syslog!("wr_i {}", wr_i % wr.len());
			for i in wr_i .. wr_i + count {
				syslog!("  > {:?}", char::try_from(wr[i % wr.len()]).unwrap());
			}
			{
				syslog!("[stream-table] {:?}", count);

				let wr: &[u8] = unsafe {
					core::slice::from_raw_parts(wr.get().cast(), 4096)
				};
				syslog!("{:#x?}", syscall::physical_address(NonNull::from(wr).cast()));
				syslog!("wr_i {}", wr_i % wr.len());
				for i in wr_i .. wr_i + count {
					syslog!("  > {:?}", char::try_from(wr[i % wr.len()]).unwrap());
				}

				wr_i += count;
				Response::write(
					&cmd,
					count,
				)
			}
			last_cmd = Some(cmd);
			i += 1;
			c.unwrap();mds.push_response(rsp);
			*/
			wr_i += count;
			Response::write(
				&cmd,
				count,
			)
		}
		last_cmd = Some(cmd);
		i += 1;
		c.unwrap();mds.push_response(rsp);
		*/
		//}

		// Mark events as handled

A git_hooks/pre-commit => git_hooks/pre-commit +3 -0
@@ 0,0 1,3 @@
#!/bin/sh

./git_hooks/rustfmt.sh || exit $?

A git_hooks/rustfmt.sh => git_hooks/rustfmt.sh +25 -0
@@ 0,0 1,25 @@
#!/bin/bash

# Shamelessly stolen from https://eugene-babichenko.github.io/blog/2018/11/08/rustfmt-git-hook/

HAS_ISSUES=0

for file in $(git diff --name-only --staged --diff-filter=d); do
	# This sucks but rustfmt doesn't allow --check with stdin because ???? idfk
	if [[ "$file" =~ '.rs'$ ]]; then
		FMT_RESULT=$(diff <(git show ":$file") <(git show ":$file" | rustfmt))
		if [ "$FMT_RESULT" != "" ]; then
			echo "$file"
			HAS_ISSUES=1
		fi
	fi
done

if [ $HAS_ISSUES -eq 0 ]; then
    exit 0
fi

echo "Your code has formatting issues in the files listed above."
echo "Run \`cargo fmt\` and stage the changes."
exit 1


A git_hooks/setup.sh => git_hooks/setup.sh +4 -0
@@ 0,0 1,4 @@
#!/bin/bash

rm -rf ../.git/hooks
ln -s ../git_hooks ../.git/hooks

M kernel/src/arch/amd64/mod.rs => kernel/src/arch/amd64/mod.rs +12 -15
@@ 8,9 8,9 @@ mod syscall;
mod tss;
pub mod r#virtual;

use crate::{driver::apic, power, scheduler, time::Monotonic};
pub use idt::{Handler, IDTEntry};
pub use syscall::{current_process, current_thread, current_thread_weak, set_current_thread};
use crate::{scheduler, driver::apic, power, time::Monotonic};

use core::mem::MaybeUninit;



@@ 36,27 36,27 @@ pub unsafe fn init() {
	GDT_PTR.assume_init_mut().activate();

	// Setup IDT
	IDT.set(61, idt::IDTEntry::new(1 * 8, __idt_wrap_handler!(int noreturn handle_timer), 0));
	IDT.set(
		61,
		idt::IDTEntry::new(1 * 8, __idt_wrap_handler!(int noreturn handle_timer), 0),
	);
	IDT.set(
		8,
		idt::IDTEntry::new(1 * 8, __idt_wrap_handler!(trap handle_double_fault), 0),
	);
	IDT.set(
		13,
		idt::IDTEntry::new(
			1 * 8,
			__idt_wrap_handler!(trap handle_double_fault),
			__idt_wrap_handler!(trap handle_general_protection_fault),
			0,
		),
	);
	IDT.set(
		13,
		idt::IDTEntry::new(1 * 8, __idt_wrap_handler!(trap handle_general_protection_fault), 0),
	);
	IDT.set(
		14,
		idt::IDTEntry::new(1 * 8, __idt_wrap_handler!(trap handle_page_fault), 0),
	);
	IDT.set(
		16,
		idt::IDTEntry::new(1 * 8, idt::NOOP, 0),
	);
	IDT.set(16, idt::IDTEntry::new(1 * 8, idt::NOOP, 0));

	IDT_PTR.write(idt::IDTPointer::new(&IDT));
	IDT_PTR.assume_init_ref().activate();


@@ 117,10 117,7 @@ pub fn halt() {
}

pub unsafe fn idt_set(irq: usize, entry: IDTEntry) {
	IDT.set(
		irq,
		entry,
	);
	IDT.set(irq, entry);
}

pub fn yield_current_thread() {

M kernel/src/arch/amd64/syscall.rs => kernel/src/arch/amd64/syscall.rs +9 -3
@@ 1,9 1,12 @@
use super::msr;
use crate::scheduler::process::Process;
use crate::scheduler::Thread;
use crate::scheduler::syscall;
use crate::scheduler::Thread;
use alloc::{
	boxed::Box,
	sync::{Arc, Weak},
};
use core::ptr::{self, NonNull};
use alloc::{boxed::Box, sync::{Arc, Weak}};

pub unsafe fn init() {
	// Enable syscall/sysenter


@@ 34,7 37,10 @@ pub unsafe fn set_current_thread(thread: Arc<Thread>) {
		Arc::from_raw(old_thr);
	}
	// Set reference to new thread.
	let user_stack = thread.user_stack.get().map_or_else(ptr::null_mut, NonNull::as_ptr);
	let user_stack = thread
		.user_stack
		.get()
		.map_or_else(ptr::null_mut, NonNull::as_ptr);
	asm!("mov gs:[0 * 8], {0}", in(reg) user_stack);
	asm!("mov gs:[1 * 8], {0}", in(reg) thread.kernel_stack.get().as_ptr());
	asm!("mov gs:[2 * 8], {0}", in(reg) thread.process.as_ptr());

M kernel/src/arch/amd64/virtual/common.rs => kernel/src/arch/amd64/virtual/common.rs +3 -9
@@ 52,9 52,8 @@ impl Entry {

	pub fn as_table(&self) -> Option<&[Entry; 512]> {
		// SAFETY: FIXME not sure how to guarantee safety :/
		self.is_table().then(|| unsafe {
			&*phys_to_virt(self.0 & !u64::try_from(Page::MASK).unwrap()).cast()
		})
		self.is_table()
			.then(|| unsafe { &*phys_to_virt(self.0 & !u64::try_from(Page::MASK).unwrap()).cast() })
	}

	pub fn as_table_mut(&mut self) -> Option<&mut [Entry; 512]> {


@@ 168,12 167,7 @@ impl From<frame::AllocateError> for MakeTableError {
	}
}

pub fn get_entry(
	table: &[Entry; 512],
	address: u64,
	level: u8,
	depth: u8,
) -> Option<&Entry> {
pub fn get_entry(table: &[Entry; 512], address: u64, level: u8, depth: u8) -> Option<&Entry> {
	let offt = usize::try_from((address >> (12 + u64::from(level + depth) * 9)) & 0x1ff).unwrap();
	let entry = &table[offt];
	if depth == 0 {

M kernel/src/arch/amd64/virtual/pml4.rs => kernel/src/arch/amd64/virtual/pml4.rs +3 -3
@@ 17,8 17,7 @@ pub fn init() {
						for l in 1..=3 {
							let e = common::get_entry_mut(root, virt, l, 3 - l);
							let ppn = e.unwrap_or_else(|_| unreachable!()).clear().unwrap();
							frame::deallocate(1, || frame::PageFrame::from_raw(ppn, 0))
								.unwrap();
							frame::deallocate(1, || frame::PageFrame::from_raw(ppn, 0)).unwrap();
						}
					}
					break;


@@ 52,7 51,8 @@ pub fn init() {
		},
		common::IDENTITY_MAP_ADDRESS,
		0,
	).unwrap();
	)
	.unwrap();
}

pub struct DumpCurrent;

M kernel/src/driver/apic/io_apic.rs => kernel/src/driver/apic/io_apic.rs +5 -2
@@ 1,6 1,6 @@
use super::RegRW;
use crate::memory::frame::PPN;
use crate::memory::r#virtual::{AddressSpace, phys_to_virt};
use crate::memory::r#virtual::{phys_to_virt, AddressSpace};

#[repr(C)]
struct IoApic {


@@ 17,7 17,10 @@ pub fn set_irq(irq: u8, apic_id: u8, vector: u8) {
		write(i + 1, read(i + 1) & 0x00ffffff | (u32::from(apic_id) << 24));

		// ... | mask | ... | delivery status | destination | delivery | vector
		write(i + 0, read(i + 0) & 0xfffe_0000 | 0 << 12 | 0 << 11 | 0b000 << 8 | u32::from(vector))
		write(
			i + 0,
			read(i + 0) & 0xfffe_0000 | 0 << 12 | 0 << 11 | 0b000 << 8 | u32::from(vector),
		)
	}
}


M kernel/src/driver/apic/local_apic.rs => kernel/src/driver/apic/local_apic.rs +55 -27
@@ 1,6 1,6 @@
use super::{RegR, RegW, RegRW};
use crate::memory::r#virtual::{AddressSpace, phys_to_virt};
use super::{RegR, RegRW, RegW};
use crate::memory::frame::PPN;
use crate::memory::r#virtual::{phys_to_virt, AddressSpace};
use core::fmt;

#[repr(C, align(4096))]


@@ 58,7 58,9 @@ fn reg_to_bitset(regs: &[RegR; 8]) -> BitSet256 {
	let mut set = [0; 2];
	// TODO don't use transmute
	let v = unsafe { core::mem::transmute::<_, &mut [u32; 8]>(&mut set) };
	regs.iter().zip(v.iter_mut()).for_each(|(r, w)| *w = r.get());
	regs.iter()
		.zip(v.iter_mut())
		.for_each(|(r, w)| *w = r.get());
	BitSet256(set)
}



@@ 66,36 68,60 @@ impl fmt::Debug for LocalApic {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		use core::fmt::DebugStruct as DS;
		let mut f = f.debug_struct(stringify!(LocalApic));
		let hex = |f: &mut DS, n, v: u32| { f.field(n, &format_args!("{:#x}", v)); };
		let set = |f: &mut DS, n, v: BitSet256| { f.field(n, &format_args!("{:?}", v)); };
		let hex = |f: &mut DS, n, v: u32| {
			f.field(n, &format_args!("{:#x}", v));
		};
		let set = |f: &mut DS, n, v: BitSet256| {
			f.field(n, &format_args!("{:?}", v));
		};

		hex(&mut f, "id",  self.id.get());
		hex(&mut f, "version",  self.version.get());
		hex(&mut f, "id", self.id.get());
		hex(&mut f, "version", self.version.get());
		hex(&mut f, "task_priority", self.task_priority.get());
		hex(&mut f, "arbitration_priority", self.arbitration_priority.get());
		hex(
			&mut f,
			"arbitration_priority",
			self.arbitration_priority.get(),
		);
		hex(&mut f, "processor_priority", self.processor_priority.get());
		// FIXME QEMU sets ESR even though it shouldn't
		// See https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-so&mut ftware-developer-vol-3a-part-1-manual.pdf
		//hex(&mut f, "remote_read",  self.remote_read.get());
		hex(&mut f, "logical_destination",  self.logical_destination.get());
		hex(&mut f, "destination_format",  self.destination_format.get());
		hex(&mut f, "spurious_interrupt_vector",  self.spurious_interrupt_vector.get());
		set(&mut f, "in_service",  self.in_service());
		set(&mut f, "trigger_mode",  self.trigger_mode());
		set(&mut f, "interrupt_request",  self.interrupt_request());
		hex(&mut f, "error_status",  self.error_status.get());
		hex(
			&mut f,
			"logical_destination",
			self.logical_destination.get(),
		);
		hex(&mut f, "destination_format", self.destination_format.get());
		hex(
			&mut f,
			"spurious_interrupt_vector",
			self.spurious_interrupt_vector.get(),
		);
		set(&mut f, "in_service", self.in_service());
		set(&mut f, "trigger_mode", self.trigger_mode());
		set(&mut f, "interrupt_request", self.interrupt_request());
		hex(&mut f, "error_status", self.error_status.get());
		// FIXME ditto
		//hex(&mut f, "lvt_cmci",  self.lvt_cmci.get());
		//hex(&mut f, "interrupt_command",  self.interrupt_command.get());
		hex(&mut f, "lvt_timer",  self.lvt_timer.get());
		hex(&mut f, "lvt_thermal_sensor",  self.lvt_thermal_sensor.get());
		hex(&mut f, "lvt_performance_monitoring_counters",  self.lvt_performance_monitoring_counters.get());
		hex(&mut f, "lvt_lint0",  self.lvt_lint0.get());
		hex(&mut f, "lvt_lint1",  self.lvt_lint1.get());
		hex(&mut f, "lvt_error",  self.lvt_error.get());
		hex(&mut f, "initial_count",  self.initial_count.get());
		hex(&mut f, "current_count",  self.current_count.get());
		hex(&mut f, "divide_configuration",  self.divide_configuration.get());
		hex(&mut f, "lvt_timer", self.lvt_timer.get());
		hex(&mut f, "lvt_thermal_sensor", self.lvt_thermal_sensor.get());
		hex(
			&mut f,
			"lvt_performance_monitoring_counters",
			self.lvt_performance_monitoring_counters.get(),
		);
		hex(&mut f, "lvt_lint0", self.lvt_lint0.get());
		hex(&mut f, "lvt_lint1", self.lvt_lint1.get());
		hex(&mut f, "lvt_error", self.lvt_error.get());
		hex(&mut f, "initial_count", self.initial_count.get());
		hex(&mut f, "current_count", self.current_count.get());
		hex(
			&mut f,
			"divide_configuration",
			self.divide_configuration.get(),
		);

		f.finish()
	}


@@ 106,9 132,11 @@ pub struct BitSet256([u128; 2]);
impl fmt::Debug for BitSet256 {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let mut f = f.debug_set();
		let mut p = |i, v, o| if v & (1u128 << i) > 0u128 {
			let i = i + o;
			f.entry(&i);
		let mut p = |i, v, o| {
			if v & (1u128 << i) > 0u128 {
				let i = i + o;
				f.entry(&i);
			}
		};
		(0..128).for_each(|i| p(i, self.0[0], 0));
		(0..128).for_each(|i| p(i, self.0[1], 128));

M kernel/src/driver/apic/mod.rs => kernel/src/driver/apic/mod.rs +9 -8
@@ 1,13 1,13 @@
pub mod local_apic;
pub mod io_apic;
pub mod local_apic;
mod reg;

use reg::*;
use crate::arch::amd64::msr;
use crate::memory::Page;
use crate::time::Monotonic;
use core::time::Duration;
use acpi::{AcpiHandler, AcpiTables};
use core::time::Duration;
use reg::*;

// No atomic is necessary as the value is read only once anyways.
static mut TICKS_PER_SECOND: u32 = 0;


@@ 34,7 34,8 @@ pub fn post_init() {
/// Smaller durations are more precise. The timer may end early if the duration
/// is too large.
pub fn set_timer_oneshot(t: Duration, irq: Option<u8>) {
	let mut ticks = t.as_nanos()
	let mut ticks = t
		.as_nanos()
		.saturating_mul(unsafe { TICKS_PER_SECOND }.into())
		.saturating_div(1_000_000_000);
	// Scale down the resolution until the ticks fit


@@ 61,7 62,9 @@ pub fn set_timer_oneshot(t: Duration, irq: Option<u8>) {

	if let Some(irq) = irq {
		let t = local_apic::get().lvt_timer.get();
		local_apic::get().lvt_timer.set(t & !(1 << 16 | 0xff) | u32::from(irq));
		local_apic::get()
			.lvt_timer
			.set(t & !(1 << 16 | 0xff) | u32::from(irq));
	}

	local_apic::get().divide_configuration.set(shift);


@@ 75,9 78,7 @@ fn calibrate_timer(t: Duration) {
	let lapic = local_apic::get();
	lapic.divide_configuration.set(0b1011); // Set divisor to 1
	lapic.initial_count.set(u32::MAX);
	while Monotonic::now() < end {
		/* pass */
	}
	while Monotonic::now() < end { /* pass */ }
	let ticks = u32::MAX - lapic.current_count.get();
	lapic.initial_count.set(0);
	unsafe {

M kernel/src/driver/hpet/mod.rs => kernel/src/driver/hpet/mod.rs +14 -5
@@ 1,8 1,8 @@
use crate::memory::r#virtual::add_identity_mapping;
use crate::time::Monotonic;
use acpi::{hpet::HpetInfo, AcpiHandler, AcpiTables};
use core::cell::UnsafeCell;
use core::{ptr, fmt};
use acpi::{AcpiTables, AcpiHandler, hpet::HpetInfo};
use core::{fmt, ptr};

// No atomic is strictly necessary since we only read from this after boot.
static mut ADDRESS: *const Hpet = core::ptr::null();


@@ 38,8 38,14 @@ impl fmt::Debug for Hpet {
		f.field("period", &(cap >> 32));
		f.field("vendor_id", &format_args!("{:#x}", (cap >> 16) as u16));
		f.field("capabilities", &format_args!("{:#x}", cap & 0xffff_ffff));
		f.field("configuration", &format_args!("{:#x}", self.configuration.get()));
		f.field("interrupt_status", &format_args!("{:#x}", self.interrupt_status.get()));
		f.field(
			"configuration",
			&format_args!("{:#x}", self.configuration.get()),
		);
		f.field(
			"interrupt_status",
			&format_args!("{:#x}", self.interrupt_status.get()),
		);
		f.field("counter", &self.counter.get());
		f.finish()
	}


@@ 85,7 91,10 @@ where
	let h = HpetInfo::new(acpi).unwrap();
	assert!(h.main_counter_is_64bits());
	unsafe {
		ADDRESS = add_identity_mapping(h.base_address.try_into().unwrap(), 4096).unwrap().cast().as_ptr();
		ADDRESS = add_identity_mapping(h.base_address.try_into().unwrap(), 4096)
			.unwrap()
			.cast()
			.as_ptr();
		// Period is in femtoseconds.
		MULTIPLIER = u128::from(hpet().capabilities_id().period()) / 1_000_000;
	}

M kernel/src/driver/mod.rs => kernel/src/driver/mod.rs +3 -3
@@ 4,12 4,12 @@ pub mod apic;
pub mod hpet;
#[cfg(feature = "driver-pci")]
pub mod pci;
pub mod uart;
#[cfg(feature = "driver-vga")]
pub mod vga;
#[cfg(feature = "driver-pic")]
pub mod pic;
pub mod rtc;
pub mod uart;
#[cfg(feature = "driver-vga")]
pub mod vga;

use crate::boot;


M kernel/src/driver/pci/device.rs => kernel/src/driver/pci/device.rs +5 -2
@@ 3,8 3,8 @@ use crate::memory::frame::PageFrame;
use crate::memory::frame::PPN;
use crate::object_table::Object;
use crate::scheduler::MemoryObject;
use pci::BaseAddress;
use alloc::boxed::Box;
use pci::BaseAddress;

/// A single PCI device.
pub struct PciDevice {


@@ 37,7 37,10 @@ impl MemoryObject for PciDevice {
impl Object for PciDevice {
	fn memory_object(&self, offset: u64) -> Option<Box<dyn MemoryObject>> {
		if offset == 0 {
			return Some(Box::new(PciDevice { device: self.device, bus: self.bus }));
			return Some(Box::new(PciDevice {
				device: self.device,
				bus: self.bus,
			}));
		}

		let index = usize::try_from(offset - 1).ok()?;

M kernel/src/driver/pci/mod.rs => kernel/src/driver/pci/mod.rs +1 -1
@@ 10,8 10,8 @@ use crate::memory::r#virtual::add_identity_mapping;
use crate::object_table;
use crate::sync::SpinLock;
use acpi::{AcpiHandler, AcpiTables, PciConfigRegions};
use pci::Pci;
use alloc::sync::Arc;
use pci::Pci;

mod device;
mod table;

M kernel/src/driver/pci/table.rs => kernel/src/driver/pci/table.rs +20 -10
@@ 1,5 1,7 @@
use crate::object_table::{Table, Query, NoneQuery, Id, Object, Ticket, Data, QueryResult, Error, Job, JobTask};
use alloc::{boxed::Box, string::String, format, sync::Arc};
use crate::object_table::{
	Data, Error, Id, Job, JobTask, NoneQuery, Object, Query, QueryResult, Table, Ticket,
};
use alloc::{boxed::Box, format, string::String, sync::Arc};

/// Table with all PCI devices.
pub struct PciTable;


@@ 11,8 13,10 @@ impl Table for PciTable {

	fn query(self: Arc<Self>, name: Option<&str>, tags: &[&str]) -> Box<dyn Query> {
		if let Some(name) = name {
			Box::new(QueryName { item: bdf_from_string(name) })
		} else { 
			Box::new(QueryName {
				item: bdf_from_string(name),
			})
		} else {
			let (mut vendor_id, mut device_id) = (None, None);
			for t in tags {
				let f = |a: &mut Option<u16>, h: &str| {


@@ 42,7 46,9 @@ impl Table for PciTable {
		let r = n_to_bdf(id.into())
			.and_then(|(bus, dev, func)| {
				let pci = super::PCI.lock();
				pci.as_ref().unwrap().get(bus, dev, func)
				pci.as_ref()
					.unwrap()
					.get(bus, dev, func)
					.map(|d| Data::Object(pci_dev_object(d, bus, dev, func)))
			})
			.ok_or_else(|| todo!());


@@ 50,7 56,10 @@ impl Table for PciTable {
	}

	fn create(self: Arc<Self>, _: &str, _: &[&str]) -> Ticket {
		let e = Error { code: 1, message: "can't create pci devices".into() };
		let e = Error {
			code: 1,
			message: "can't create pci devices".into(),
		};
		Ticket::new_complete(Err(e))
	}



@@ 119,7 128,7 @@ fn bdf_to_string(bus: u8, dev: u8, func: u8) -> String {
}

fn bdf_from_string(s: &str) -> Option<(u8, u8, u8)> {
	let (bus, s)    = s.split_once(':')?;
	let (bus, s) = s.split_once(':')?;
	let (dev, func) = s.split_once('.')?;
	Some((bus.parse().ok()?, dev.parse().ok()?, func.parse().ok()?))
}


@@ 134,13 143,14 @@ fn pci_dev_query_result(h: pci::Header, bus: u8, dev: u8, func: u8) -> QueryResu
	let tags = [
		format!("vendor-id:{:04x}", h.vendor_id()).into(),
		format!("device-id:{:04x}", h.device_id()).into(),
	].into();
	]
	.into();
	QueryResult { id, name, tags }
}

fn n_to_bdf(n: u64) -> Option<(u8, u8, u8)> {
	let func = u8::try_from((n >> 0) & 0x07).unwrap();
	let dev  = u8::try_from((n >> 3) & 0x1f).unwrap();
	let bus  = u8::try_from((n >> 8) & 0xff).ok()?;
	let dev = u8::try_from((n >> 3) & 0x1f).unwrap();
	let bus = u8::try_from((n >> 8) & 0xff).ok()?;
	Some((bus, dev, func))
}

M kernel/src/memory/frame/dma_frame.rs => kernel/src/memory/frame/dma_frame.rs +1 -4
@@ 13,10 13,7 @@ pub struct DMAFrame {
impl DMAFrame {
	pub fn new(count: PPNBox) -> Result<Self, frame::AllocateContiguousError> {
		frame::allocate_contiguous(NonZeroUsize::new(count.try_into().unwrap()).unwrap())
			.map(|base|
		Self {
			base, count
		})
			.map(|base| Self { base, count })
	}
}


M kernel/src/memory/frame/mod.rs => kernel/src/memory/frame/mod.rs +5 -2
@@ 9,8 9,8 @@ pub use dma_frame::*;

use super::Page;
use core::fmt;
use core::ptr;
use core::num::NonZeroUsize;
use core::ptr;

/// A Physical Page Number.
///


@@ 236,7 236,10 @@ where

/// Allocate a physically contiguous range of pages.
pub fn allocate_contiguous(count: NonZeroUsize) -> Result<PPN, AllocateContiguousError> {
	dumb_stack::STACK.lock().pop_contiguous_range(count).ok_or(AllocateContiguousError::OutOfFrames)
	dumb_stack::STACK
		.lock()
		.pop_contiguous_range(count)
		.ok_or(AllocateContiguousError::OutOfFrames)
}

/// Free a range of pages.

M kernel/src/memory/heap/mod.rs => kernel/src/memory/heap/mod.rs +1 -4
@@ 11,10 11,7 @@ struct Global;
unsafe impl GlobalAlloc for Global {
	unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
		let c = NonZeroUsize::new(Page::min_pages_for_bytes(layout.size())).unwrap();
		frame::allocate_contiguous(c)
			.unwrap()
			.as_ptr()
			.cast()
		frame::allocate_contiguous(c).unwrap().as_ptr().cast()
	}

	unsafe fn dealloc(&self, _: *mut u8, _: Layout) {}

M kernel/src/memory/virtual/address_space.rs => kernel/src/memory/virtual/address_space.rs +2 -5
@@ 1,6 1,6 @@
use crate::arch::r#virtual;
use crate::memory::{
	r#virtual::{MapError, RWX, PPN},
	r#virtual::{MapError, PPN, RWX},
	Page,
};
use crate::scheduler::MemoryObject;


@@ 30,7 30,6 @@ impl AddressSpace {
		rwx: RWX,
		hint_color: u8,
	) -> Result<MemoryObjectHandle, MapError> {

		let base = base.unwrap(); // TODO
		let count = object
			.physical_pages()


@@ 87,9 86,7 @@ impl AddressSpace {
	/// `size` must be a multiple of the page size.
	pub fn identity_map(ppn: PPN, size: usize) -> bool {
		assert_eq!(size % Page::SIZE, 0);
		unsafe {
			r#virtual::add_identity_mapping(ppn.as_phys(), size).is_ok()
		}
		unsafe { r#virtual::add_identity_mapping(ppn.as_phys(), size).is_ok() }
	}
}


M kernel/src/object_table/mod.rs => kernel/src/object_table/mod.rs +45 -15
@@ 9,7 9,11 @@ mod streaming;

use crate::scheduler::MemoryObject;
use crate::sync::SpinLock;
use alloc::{boxed::Box, vec::Vec, sync::{Arc, Weak}};
use alloc::{
	boxed::Box,
	sync::{Arc, Weak},
	vec::Vec,
};
use core::fmt;
use core::future::Future;
use core::pin::Pin;


@@ 23,7 27,7 @@ static TABLES: SpinLock<Vec<Weak<dyn Table>>> = SpinLock::new(Vec::new());
/// A table of objects.
pub trait Table
where
	Self: Object, // This allows putting tables in the object list of each process.
	Self: Object,
{
	/// The name of this table.
	fn name(&self) -> &str;


@@ 106,7 110,12 @@ impl EventListener {
	#[allow(dead_code)]
	fn new() -> (Self, EventWaker) {
		let shared = Arc::new(SpinLock::default());
		(Self { shared: shared.clone() }, EventWaker { shared })
		(
			Self {
				shared: shared.clone(),
			},
			EventWaker { shared },
		)
	}
}



@@ 125,7 134,7 @@ impl Future for EventListener {
	fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
		let mut l = self.shared.lock();
		if let Some(e) = l.1.take() {
			return Poll::Ready(e)
			return Poll::Ready(e);
		}
		l.0 = Some(cx.waker().clone());
		Poll::Pending


@@ 160,8 169,8 @@ pub struct Job {
#[repr(u8)]
pub enum JobType {
	#[default]
	Open  = 0,
	Read  = 1,
	Open = 0,
	Read = 1,
	Write = 2,
}



@@ 231,13 240,25 @@ pub struct Ticket {

impl Ticket {
	pub fn new_complete(status: Result<Data, Error>) -> Self {
		let inner = SpinLock::new(TicketInner { waker: None, status: Some(status) }).into();
		let inner = SpinLock::new(TicketInner {
			waker: None,
			status: Some(status),
		})
		.into();
		Self { inner }
	}

	pub fn new() -> (Self, TicketWaker) {
		let inner = Arc::new(SpinLock::new(TicketInner { waker: None, status: None }));
		(Self { inner: inner.clone() }, TicketWaker { inner })
		let inner = Arc::new(SpinLock::new(TicketInner {
			waker: None,
			status: None,
		}));
		(
			Self {
				inner: inner.clone(),
			},
			TicketWaker { inner },
		)
	}
}



@@ 295,7 316,12 @@ pub struct JobTask {
impl JobTask {
	pub fn new(job: Option<Job>) -> (Self, JobWaker) {
		let shared = Arc::new(SpinLock::new((None, job)));
		(Self { shared: shared.clone() }, JobWaker { shared })
		(
			Self {
				shared: shared.clone(),
			},
			JobWaker { shared },
		)
	}
}



@@ 346,7 372,11 @@ pub fn find_table(name: &str) -> Option<TableId> {
}

/// Perform a query on the given table if it exists.
pub fn query(table_id: TableId, name: Option<&str>, tags: &[&str]) -> Result<Box<dyn Query>, QueryError> {
pub fn query(
	table_id: TableId,
	name: Option<&str>,
	tags: &[&str],
) -> Result<Box<dyn Query>, QueryError> {
	TABLES
		.lock()
		.get(usize::try_from(table_id.0).unwrap())


@@ 392,10 422,10 @@ pub fn next_table(id: Option<TableId>) -> Option<(Box<str>, TableId)> {
			.iter()
			.enumerate()
			.find_map(|(i, t)| t.upgrade().map(|t| (i, t))),
		Some(id) => tbl
			.iter()
			.enumerate()
			.find_map(|(i, t)| t.upgrade().and_then(|t| (i > id.0 as usize).then(|| (i, t)))),
		Some(id) => tbl.iter().enumerate().find_map(|(i, t)| {
			t.upgrade()
				.and_then(|t| (i > id.0 as usize).then(|| (i, t)))
		}),
	}?;
	Some((tbl.name().into(), TableId(id as u32)))
}

M kernel/src/object_table/streaming.rs => kernel/src/object_table/streaming.rs +30 -18
@@ 1,7 1,11 @@
use super::*;
use crate::sync::Mutex;
use alloc::{
	boxed::Box,
	sync::{Arc, Weak},
	vec::Vec,
};
use core::sync::atomic::{AtomicU32, Ordering};
use alloc::{boxed::Box, sync::{Arc, Weak}, vec::Vec};

#[derive(Default)]
pub struct StreamingTable {


@@ 15,7 19,11 @@ pub struct StreamingTable {

impl StreamingTable {
	pub fn new(name: Box<str>) -> Arc<Self> {
		Self { name, ..Default::default() }.into()
		Self {
			name,
			..Default::default()
		}
		.into()
	}

	fn submit_job(&self, job: StreamJob, id: Id) -> Ticket {


@@ 69,12 77,15 @@ impl Table for StreamingTable {
		let (_, id, tw) = c.next().ok_or(())?;
		match job.ty {
			JobType::Open => {
				let obj = Arc::new(StreamObject { id, table: Arc::downgrade(&self) });
				let obj = Arc::new(StreamObject {
					id,
					table: Arc::downgrade(&self),
				});
				tw.complete(Ok(Data::Object(obj)));
			}
			JobType::Write => {
				tw.complete(Ok(Data::Usize(job.operation_size.try_into().unwrap())));
			},
			}
			JobType::Read => todo!(),
		}
		assert!(c.next().is_none());


@@ 114,10 125,13 @@ impl Object for StreamObject {
	}

	fn write(&self, _: u64, data: &[u8]) -> Result<Ticket, ()> {
		self.table.upgrade().map(|tbl| {
			let job = StreamJob::Write { data: data.into() };
			tbl.submit_job(job, self.id)
		}).ok_or(())
		self.table
			.upgrade()
			.map(|tbl| {
				let job = StreamJob::Write { data: data.into() };
				tbl.submit_job(job, self.id)
			})
			.ok_or(())
	}
}



@@ 135,16 149,14 @@ impl StreamJob {
				object_id,
				..Default::default()
			},
			StreamJob::Write { data } => {
				Job {
					ty: JobType::Write,
					job_id,
					object_id,
					operation_size: data.len().try_into().unwrap(),
					buffer: data,
					..Default::default()
				}
			}
			StreamJob::Write { data } => Job {
				ty: JobType::Write,
				job_id,
				object_id,
				operation_size: data.len().try_into().unwrap(),
				buffer: data,
				..Default::default()
			},
		}
	}
}

M kernel/src/scheduler/mod.rs => kernel/src/scheduler/mod.rs +4 -4
@@ 1,19 1,19 @@
mod memory_object;
pub mod process;
mod round_robin;
pub mod syscall;
mod thread;
mod round_robin;
mod waker;

use core::time::Duration;
use crate::time::Monotonic;
use alloc::sync::Arc;
use core::future::Future;
use core::pin::Pin;
use core::marker::Unpin;
use core::pin::Pin;
use core::task::{Context, Poll};
use core::time::Duration;
pub use memory_object::*;
pub use thread::Thread;
use alloc::sync::Arc;

pub use round_robin::count as thread_count;


M kernel/src/scheduler/process/elf.rs => kernel/src/scheduler/process/elf.rs +2 -2
@@ 1,13 1,13 @@
use crate::scheduler::Thread;
use crate::memory::frame;
use crate::memory::frame::PPN;
use crate::memory::r#virtual::{virt_to_phys, MapError, RWX};
use crate::memory::Page;
use crate::scheduler::Thread;
use alloc::{boxed::Box, sync::Arc};
use core::mem;
use core::num::NonZeroUsize;
use core::ops::Range;
use core::ptr::NonNull;
use alloc::{boxed::Box, sync::Arc};

#[repr(C)]
struct FileHeader {

M kernel/src/scheduler/process/mod.rs => kernel/src/scheduler/process/mod.rs +8 -8
@@ 3,11 3,11 @@ mod elf;
use super::{MemoryObject, Thread};
use crate::arch;
use crate::memory::frame;
use crate::memory::r#virtual::{AddressSpace, MapError, RWX, MemoryObjectHandle};
use crate::memory::r#virtual::{AddressSpace, MapError, MemoryObjectHandle, RWX};
use crate::memory::Page;
use crate::object_table::{Object, Query};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use core::ptr::NonNull;
use alloc::{boxed::Box, vec::Vec, sync::Arc};

pub struct Process {
	address_space: AddressSpace,


@@ 54,9 54,9 @@ impl Process {
		base: Option<NonNull<Page>>,
		object: Box<dyn MemoryObject>,
		rwx: RWX,
	) -> Result<MemoryObjectHandle, MapError>
	{
		self.address_space.map_object(base, object.into(), rwx, self.hint_color)
	) -> Result<MemoryObjectHandle, MapError> {
		self.address_space
			.map_object(base, object.into(), rwx, self.hint_color)
	}

	/// Map a memory object to a memory range.


@@ 66,10 66,10 @@ impl Process {
		base: Option<NonNull<Page>>,
		offset: u64,
		rwx: RWX,
	) -> Result<MemoryObjectHandle, MapError>
	{
	) -> Result<MemoryObjectHandle, MapError> {
		let obj = self.objects[handle.0].memory_object(offset).unwrap();
		self.address_space.map_object(base, obj, rwx, self.hint_color)
		self.address_space
			.map_object(base, obj, rwx, self.hint_color)
	}

	/// Get a reference to a memory object.

M kernel/src/scheduler/round_robin.rs => kernel/src/scheduler/round_robin.rs +7 -2
@@ 2,8 2,11 @@

use super::Thread;
use crate::sync::SpinLock;
use alloc::{
	boxed::Box,
	sync::{Arc, Weak},
};
use core::ptr::NonNull;
use alloc::{boxed::Box, sync::{Arc, Weak}};

static THREAD_LIST: SpinLock<(usize, Option<NonNull<Node>>)> = SpinLock::new((0, None));



@@ 47,7 50,9 @@ pub fn next() -> Option<Arc<Thread>> {
			n.next
		};
		let c = unsafe { curr.as_mut() };
		drop(unsafe { Box::from_raw(c.next.as_ptr()); });
		drop(unsafe {
			Box::from_raw(c.next.as_ptr());
		});
		if c.next == curr {
			l.1 = None;
			return None;

M kernel/src/scheduler/syscall.rs => kernel/src/scheduler/syscall.rs +177 -42
@@ 1,14 1,18 @@
use crate::ffi;
use crate::memory::{frame, r#virtual::RWX, Page};
use crate::object_table;
use crate::object_table::{Id, TableId, Job, JobId, JobType};
use crate::memory::{frame, Page, r#virtual::RWX};
use crate::scheduler::{process::Process, syscall::frame::DMAFrame, Thread};
use crate::object_table::{Id, Job, JobId, JobType, TableId};
use crate::scheduler::process::ObjectHandle;
use crate::ffi;
use crate::scheduler::{process::Process, syscall::frame::DMAFrame, Thread};
use crate::time::Monotonic;
use alloc::{
	boxed::Box,
	sync::{Arc, Weak},
	vec::Vec,
};
use core::mem;
use core::ptr::NonNull;
use core::time::Duration;
use alloc::{boxed::Box, vec::Vec, sync::{Arc, Weak}};

#[derive(Clone, Copy)]
#[repr(C)]


@@ 54,25 58,38 @@ extern "C" fn syslog(ptr: usize, len: usize, _: usize, _: usize, _: usize, _: us
	}
}

extern "C" fn alloc_dma(base: usize, size: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn alloc_dma(
	base: usize,
	size: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	let rwx = RWX::RW;
	let base = NonNull::new(base as *mut _);
	let count = (size + Page::MASK) / Page::SIZE;
	let frame = DMAFrame::new(count.try_into().unwrap()).unwrap();
	Process::current().map_memory_object(base, Box::new(frame), rwx).unwrap();
	Process::current()
		.map_memory_object(base, Box::new(frame), rwx)
		.unwrap();
	Return {
		status: 0,
		value: 0,
	}
}

extern "C" fn physical_address(address: usize, _: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn physical_address(
	address: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	let address = NonNull::new(address as *mut _).unwrap();
	let value = Process::current().get_physical_address(address).unwrap().0;
	Return {
		status: 0,
		value,
	}
	Return { status: 0, value }
}

#[repr(C)]


@@ 82,13 99,22 @@ struct TableInfo {
}

/// Return the name and ID of the table after another table, or the first table if `id == usize::MAX`.
extern "C" fn next_table(id: usize, info_ptr: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn next_table(
	id: usize,
	info_ptr: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	let id = (id != usize::MAX).then(|| TableId::from(u32::try_from(id).unwrap()));
	let (name, id) = match object_table::next_table(id) {
		Some(p) => p,
		None => return Return {
			status: 1,
			value: 0,
		None => {
			return Return {
				status: 1,
				value: 0,
			}
		}
	};
	// SAFETY: FIXME


@@ 104,7 130,14 @@ extern "C" fn next_table(id: usize, info_ptr: usize, _: usize, _: usize, _: usiz
	}
}

extern "C" fn query_table(id: usize, name: usize, name_len: usize, tags: usize, tags_len: usize, _: usize) -> Return {
extern "C" fn query_table(
	id: usize,
	name: usize,
	name_len: usize,
	tags: usize,
	tags_len: usize,
	_: usize,
) -> Return {
	let id = TableId::from(u32::try_from(id).unwrap());
	// SAFETY: FIXME
	let (name, tags) = unsafe {


@@ 137,13 170,23 @@ struct ObjectInfo {
	tags_offsets: [u32; 255],
}

extern "C" fn query_next(handle: usize, info: usize, string_buffer: usize, string_buffer_len: usize, _: usize, _: usize) -> Return {
extern "C" fn query_next(
	handle: usize,
	info: usize,
	string_buffer: usize,
	string_buffer_len: usize,
	_: usize,
	_: usize,
) -> Return {
	// SAFETY: FIXME
	let info = unsafe { &mut *(info as *mut ObjectInfo) };
	let string_buffer = unsafe {
		core::slice::from_raw_parts_mut(string_buffer as *mut u8, string_buffer_len)
	};
	match Process::current().get_query_mut(handle.into()).unwrap().next() {
	let string_buffer =
		unsafe { core::slice::from_raw_parts_mut(string_buffer as *mut u8, string_buffer_len) };
	match Process::current()
		.get_query_mut(handle.into())
		.unwrap()
		.next()
	{
		None => Return {
			status: 1,
			value: 0,


@@ 168,11 211,19 @@ extern "C" fn query_next(handle: usize, info: usize, string_buffer: usize, strin
	}
}

extern "C" fn open_object(table_id: usize, id_l: usize, id_h: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn open_object(
	table_id: usize,
	id_l: usize,
	id_h: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	let table_id = match mem::size_of_val(&table_id) {
		4 | 8 | 16 => u32::try_from(table_id).unwrap(),
		s => unreachable!("unsupported usize size of {}", s),
	}.into();
	}
	.into();
	let id = Id::from(merge_u64(id_l, id_h));
	let ticket = object_table::get(table_id, id).unwrap();
	let obj = super::block_on(ticket).unwrap().into_object().unwrap();


@@ 183,37 234,67 @@ extern "C" fn open_object(table_id: usize, id_l: usize, id_h: usize, _: usize, _
	}
}

extern "C" fn map_object(handle: usize, base: usize, offset_l: usize, offset_h_or_length: usize, length_or_rwx: usize, rwx: usize) -> Return {
extern "C" fn map_object(
	handle: usize,
	base: usize,
	offset_l: usize,
	offset_h_or_length: usize,
	length_or_rwx: usize,
	rwx: usize,
) -> Return {
	let (offset, _length, _rwx) = match mem::size_of_val(&offset_l) {
		4 => ((offset_h_or_length as u64) << 32 | offset_l as u64, length_or_rwx, rwx),
		4 => (
			(offset_h_or_length as u64) << 32 | offset_l as u64,
			length_or_rwx,
			rwx,
		),
		8 | 16 => (offset_l as u64, offset_h_or_length, length_or_rwx),
		s => unreachable!("unsupported usize size of {}", s),
	};
	let handle = ObjectHandle::from(handle);
	let base = NonNull::new(base as *mut _);
	Process::current().map_memory_object_2(handle, base, offset, RWX::RW).unwrap();
	Process::current()
		.map_memory_object_2(handle, base, offset, RWX::RW)
		.unwrap();
	Return {
		status: 0,
		value: base.unwrap().as_ptr() as usize,
	}
}

extern "C" fn read_object(handle: usize, base: usize, _length: usize, offset_l: usize, offset_h: usize, _: usize) -> Return {
extern "C" fn read_object(
	handle: usize,
	base: usize,
	_length: usize,
	offset_l: usize,
	offset_h: usize,
	_: usize,
) -> Return {
	let _handle = ObjectHandle::from(handle);
	let _offset = merge_u64(offset_l, offset_h);
	let _base = NonNull::new(base as *mut u8).unwrap();
	todo!()
}

extern "C" fn write_object(handle: usize, base: usize, length: usize, offset_l: usize, offset_h: usize, _: usize) -> Return {
extern "C" fn write_object(
	handle: usize,
	base: usize,
	length: usize,
	offset_l: usize,
	offset_h: usize,
	_: usize,
) -> Return {
	let handle = ObjectHandle::from(handle);
	let offset = merge_u64(offset_l, offset_h);
	let base = NonNull::new(base as *mut u8).unwrap();
	let data = unsafe { core::slice::from_raw_parts(base.as_ptr(), length) };

	let written = Process::current().get_object(handle).unwrap().write(offset, data).unwrap();
	let written = super::block_on(written).unwrap()
		.into_usize().unwrap();
	let written = Process::current()
		.get_object(handle)
		.unwrap()
		.write(offset, data)
		.unwrap();
	let written = super::block_on(written).unwrap().into_usize().unwrap();

	Return {
		status: 0,


@@ 221,7 302,14 @@ extern "C" fn write_object(handle: usize, base: usize, length: usize, offset_l: 
	}
}

extern "C" fn poll_object(_handle: usize, _: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn poll_object(
	_handle: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	todo!();
	/*
	let handle = ObjectHandle::from(handle);


@@ 234,7 322,14 @@ extern "C" fn poll_object(_handle: usize, _: usize, _: usize, _: usize, _: usize
	*/
}

extern "C" fn create_table(name: usize, name_len: usize, ty: usize, _options: usize, _: usize, _: usize) -> Return {
extern "C" fn create_table(
	name: usize,
	name_len: usize,
	ty: usize,
	_options: usize,
	_: usize,
	_: usize,
) -> Return {
	let name = NonNull::new(name as *mut u8).unwrap();
	assert!(name_len <= 255, "name too long");
	let name = unsafe { core::slice::from_raw_parts(name.as_ptr(), name_len) };


@@ 306,7 401,7 @@ impl TryFrom<FfiJob> for Job {
		let buffer = unsafe {
			core::slice::from_raw_parts(
				fj.buffer.unwrap().as_ptr(),
				fj.buffer_size.try_into().unwrap()
				fj.buffer_size.try_into().unwrap(),
			)
		};
		Ok(Self {


@@ 320,14 415,31 @@ impl TryFrom<FfiJob> for Job {
	}
}

extern "C" fn take_table_job(handle: usize, job_ptr: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn take_table_job(
	handle: usize,
	job_ptr: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	assert_ne!(job_ptr, 0);

	let handle = ObjectHandle::from(handle);
	let tbl = Process::current().get_object(handle).unwrap().clone().as_table().unwrap();
	let tbl = Process::current()
		.get_object(handle)
		.unwrap()
		.clone()
		.as_table()
		.unwrap();

	let mut job = unsafe { &mut *(job_ptr as *mut FfiJob) };
	let copy_to = unsafe { core::slice::from_raw_parts_mut(job.buffer.unwrap().as_ptr(), job.buffer_size.try_into().unwrap()) };
	let copy_to = unsafe {
		core::slice::from_raw_parts_mut(
			job.buffer.unwrap().as_ptr(),
			job.buffer_size.try_into().unwrap(),
		)
	};
	let info = super::block_on(tbl.take_job());
	job.ty = info.ty.into();
	job.flags = info.flags;


@@ 344,11 456,23 @@ extern "C" fn take_table_job(handle: usize, job_ptr: usize, _: usize, _: usize, 
	}
}

extern "C" fn finish_table_job(handle: usize, job_ptr: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn finish_table_job(
	handle: usize,
	job_ptr: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	assert_ne!(job_ptr, 0);

	let handle = ObjectHandle::from(handle);
	let tbl = Process::current().get_object(handle).unwrap().clone().as_table().unwrap();
	let tbl = Process::current()
		.get_object(handle)
		.unwrap()
		.clone()
		.as_table()
		.unwrap();

	let data = unsafe { (job_ptr as *mut FfiJob).read() };



@@ 360,10 484,21 @@ extern "C" fn finish_table_job(handle: usize, job_ptr: usize, _: usize, _: usize
	}
}

extern "C" fn sleep(time_l: usize, time_h: usize, _: usize, _: usize, _: usize, _: usize) -> Return {
extern "C" fn sleep(
	time_l: usize,
	time_h: usize,
	_: usize,
	_: usize,
	_: usize,
	_: usize,
) -> Return {
	let time = merge_u64(time_l, time_h);
	let time = Duration::from_micros(time.into());
	unsafe { for _ in 0..1000000000usize { asm!("") } }
	unsafe {
		for _ in 0..1000000000usize {
			asm!("")
		}
	}

	Thread::current().set_sleep_until(Monotonic::now().saturating_add(time));
	Thread::yield_current();

M kernel/src/scheduler/thread.rs => kernel/src/scheduler/thread.rs +8 -4
@@ 2,11 2,11 @@ use super::process::Process;
use crate::arch;
use crate::memory::frame;
use crate::time::Monotonic;
use alloc::sync::{Arc, Weak};
use core::cell::Cell;
use core::num::NonZeroUsize;
use core::ptr::NonNull;
use core::time::Duration;
use alloc::sync::{Arc, Weak};

pub struct Thread {
	pub user_stack: Cell<Option<NonNull<usize>>>,


@@ 16,7 16,10 @@ pub struct Thread {
}

impl Thread {
	pub fn new(start: usize, process: NonNull<Process>) -> Result<Self, frame::AllocateContiguousError> {
	pub fn new(
		start: usize,
		process: NonNull<Process>,
	) -> Result<Self, frame::AllocateContiguousError> {
		unsafe {
			let kernel_stack_base = frame::allocate_contiguous(NonZeroUsize::new(1).unwrap())?
				.as_ptr()


@@ 53,7 56,8 @@ impl Thread {

		// iretq is the only way to preserve all registers
		unsafe {
			asm!("
			asm!(
				"
				# Set kernel stack
				mov		rsp, gs:[8]



@@ 92,7 96,7 @@ impl Thread {

				rex64 iretq
			",
			options(noreturn),
				options(noreturn),
			);
		}
	}

M kernel/src/scheduler/waker.rs => kernel/src/scheduler/waker.rs +1 -1
@@ 1,8 1,8 @@
//! Waker for asynchronous operations.

use super::Thread;
use core::task::{RawWaker, RawWakerVTable, Waker};
use alloc::sync::Weak;
use core::task::{RawWaker, RawWakerVTable, Waker};

static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);


M kernel/src/sync/mod.rs => kernel/src/sync/mod.rs +2 -2
@@ 1,5 1,5 @@
pub mod spinlock;
pub mod mutex;
pub mod spinlock;

pub use spinlock::SpinLock;
pub use mutex::Mutex;
pub use spinlock::SpinLock;

M kernel/src/time/mod.rs => kernel/src/time/mod.rs +18 -7
@@ 1,23 1,31 @@
use core::time::Duration;
use core::fmt;
use core::time::Duration;

#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Monotonic {
	nanoseconds: u64
	nanoseconds: u64,
}

impl Monotonic {
	pub const ZERO: Self = Self { nanoseconds: 0 };
	pub const MAX: Self = Self { nanoseconds: u64::MAX };
	pub const MAX: Self = Self {
		nanoseconds: u64::MAX,
	};

	pub fn from_nanoseconds(ns: u128) -> Self {
		Self { nanoseconds: ns.try_into().expect("nanoseconds too far in the future") }
		Self {
			nanoseconds: ns.try_into().expect("nanoseconds too far in the future"),
		}
	}

	#[allow(dead_code)]
	pub fn from_seconds(s: u128) -> Self {
		Self { nanoseconds: (s * 1_000_000_000).try_into().expect("seconds too far in the future") }
		Self {
			nanoseconds: (s * 1_000_000_000)
				.try_into()
				.expect("seconds too far in the future"),
		}
	}

	pub fn checked_add(self, dt: Duration) -> Option<Self> {


@@ 29,12 37,15 @@ impl Monotonic {

	pub fn saturating_add(self, dt: Duration) -> Self {
		self.checked_add(dt).unwrap_or(Self::MAX)
	}	
	}

	/// Returns the `Duration` until the given `Monotonic`. This is `None` if the
	/// given `Monotonic` has already passed.
	pub fn duration_until(self, until: Self) -> Option<Duration> {
		until.nanoseconds.checked_sub(self.nanoseconds).map(Duration::from_nanos)
		until
			.nanoseconds
			.checked_sub(self.nanoseconds)
			.map(Duration::from_nanos)
	}
}


M lib/rust/kernel/src/syscall.rs => lib/rust/kernel/src/syscall.rs +38 -12
@@ 92,13 92,21 @@ impl<T> Slice<T> {

impl<T> From<&[T]> for Slice<T> {
	fn from(s: &[T]) -> Self {
		Self { ptr: NonNull::from(s).as_non_null_ptr(), len: s.len(), _marker: PhantomData }
		Self {
			ptr: NonNull::from(s).as_non_null_ptr(),
			len: s.len(),
			_marker: PhantomData,
		}
	}
}

impl<T, const N: usize> From<&[T; N]> for Slice<T> {
	fn from(s: &[T; N]) -> Self {
		Self { ptr: NonNull::new(s.as_ptr() as *mut _).unwrap(), len: s.len(), _marker: PhantomData }
		Self {
			ptr: NonNull::new(s.as_ptr() as *mut _).unwrap(),
			len: s.len(),
			_marker: PhantomData,
		}
	}
}



@@ 114,7 122,10 @@ pub struct ObjectInfo<'a> {

impl<'a> ObjectInfo<'a> {
	pub fn new(string_buffer: &'a mut [u8]) -> Self {
		Self { string_buffer, ..Default::default() }
		Self {
			string_buffer,
			..Default::default()
		}
	}

	pub fn name(&self) -> &[u8] {


@@ 124,7 135,7 @@ impl<'a> ObjectInfo<'a> {
	pub fn tag(&'a self, index: usize) -> &'a [u8] {
		let index = self.tags_offsets[index] as usize;
		let len = usize::from(self.string_buffer[index]);
		&self.string_buffer[index + 1 .. index + 1 + len]
		&self.string_buffer[index + 1..index + 1 + len]
	}

	pub fn tags_count(&self) -> usize {


@@ 158,7 169,9 @@ impl fmt::Debug for ObjectInfo<'_> {
			fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
				let s = self.0.take().unwrap();
				let mut f = f.debug_list();
				s.for_each(|e| { f.entry(&ByteStr(e)); });
				s.for_each(|e| {
					f.entry(&ByteStr(e));
				});
				f.finish()
			}
		}


@@ 166,7 179,10 @@ impl fmt::Debug for ObjectInfo<'_> {
		let mut f = f.debug_struct(stringify!(ObjectInfo));
		f.field("id", &self.id);
		f.field("name", &ByteStr(self.name()));
		f.field("tags", &S(Cell::new(Some((0..self.tags_count()).map(|i| self.tag(i))))));
		f.field(
			"tags",
			&S(Cell::new(Some((0..self.tags_count()).map(|i| self.tag(i))))),
		);
		f.finish()
	}
}


@@ 213,7 229,10 @@ impl<'a> Job<'a> {
	pub const WRITE: u8 = 2;

	pub unsafe fn data(&self) -> &'a [u8] {
		core::slice::from_raw_parts(self.buffer.unwrap().as_ptr(), self.operation_size.try_into().unwrap())
		core::slice::from_raw_parts(
			self.buffer.unwrap().as_ptr(),
			self.operation_size.try_into().unwrap(),
		)
	}
}



@@ 301,7 320,11 @@ pub fn next_table(id: Option<TableId>) -> Option<(TableId, TableInfo)> {
}

#[inline]
pub fn query_table(id: TableId, name: Option<&[u8]>, tags: &[Slice<u8>]) -> Result<QueryHandle, (NonZeroUsize, usize)> {
pub fn query_table(
	id: TableId,
	name: Option<&[u8]>,
	tags: &[Slice<u8>],
) -> Result<QueryHandle, (NonZeroUsize, usize)> {
	let (status, value): (usize, usize);
	unsafe {
		asm!(


@@ 360,7 383,12 @@ pub fn open_object(table_id: TableId, id: Id) -> Result<Handle, (NonZeroUsize, u
}

#[inline]
pub fn map_object(handle: Handle, base: Option<NonNull<Page>>, offset: u64, length: usize) -> Result<NonNull<Page>, (NonZeroUsize, usize)> {
pub fn map_object(
	handle: Handle,
	base: Option<NonNull<Page>>,
	offset: u64,
	length: usize,
) -> Result<NonNull<Page>, (NonZeroUsize, usize)> {
	let (status, value): (usize, usize);
	unsafe {
		asm!(


@@ 379,7 407,6 @@ pub fn map_object(handle: Handle, base: Option<NonNull<Page>>, offset: u64, leng
	ret(status, value).map(|v| NonNull::new(v as *mut _).unwrap())
}


#[inline]
pub fn sleep(duration: Duration) {
	let micros = u64::try_from(duration.as_micros()).unwrap_or(u64::MAX);


@@ 479,8 506,7 @@ impl fmt::Write for SysLog {
	#[optimize(size)]
	fn write_str(&mut self, s: &str) -> fmt::Result {
		for c in s.bytes() {
			if c == b'\n'
				|| usize::from(self.index) >= self.buffer.len() {
			if c == b'\n' || usize::from(self.index) >= self.buffer.len() {
				self.flush();
			}
			if c != b'\n' {

M lib/rust/virtio/src/queue.rs => lib/rust/virtio/src/queue.rs +4 -3
@@ 266,7 266,6 @@ impl<'a> Queue<'a> {
	///
	/// The amount of buffers collected.
	pub fn collect_used(&mut self, mut callback: impl FnMut(u16, u64, u32)) -> usize {

		atomic::fence(Ordering::Acquire);
		let (head, ring) = used_ring!(self);
		let table = descriptors_table!(self);


@@ 305,8 304,10 @@ impl<'a> Queue<'a> {
		&mut self,
		mut callback: impl FnMut(u16, u64, u32),
		mut wait_fn: impl FnMut(),
	) { 
		while usize::from(self.free_count) != self.free_descriptors.len() && self.collect_used(&mut callback) == 0 {
	) {
		while usize::from(self.free_count) != self.free_descriptors.len()
			&& self.collect_used(&mut callback) == 0
		{
			//callback(self.free_count, self.free_descriptors.len() as u64, u32::MAX);
			wait_fn();
		}