***: fix all warnings and clippy stuff

This commit is contained in:
Mark Poliakov 2023-08-02 20:43:21 +03:00
parent c9af9b143a
commit da91126293
30 changed files with 467 additions and 439 deletions

View File

@ -20,7 +20,6 @@ cfg-if = "1.0.0"
bitmap-font = { version = "0.3.0" }
embedded-graphics = "0.8.0"
git-version = "0.3.5"
acpi = "4.1.1"
[dependencies.elf]
version = "0.7.2"
@ -35,3 +34,4 @@ aarch64-cpu = "9.3.1"
[target.'cfg(target_arch = "x86_64")'.dependencies]
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
aml = "0.16.4"
acpi = "4.1.1"

View File

@ -1,12 +1,15 @@
//! AArch64-specific task context implementation
use core::{arch::global_asm, cell::UnsafeCell};
use abi::error::Error;
use abi::{error::Error, process::ExitCode};
use alloc::boxed::Box;
use crate::mem::{
use crate::{
mem::{
phys::{self, PageUsage},
ConvertAddress,
},
task::process::Process,
};
struct StackBuilder {
@ -82,6 +85,11 @@ impl StackBuilder {
}
impl TaskContext {
/// Extra number of bytes to offset the user stack pointer
pub const USER_STACK_EXTRA_ALIGN: usize = 0;
/// Extra number of bytes to offset the signal stack pointer
pub const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;
/// Constructs a kernel thread context. For a more convenient way of constructing kernel
/// processes, see [TaskContext::kernel_closure()].
pub fn kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<Self, Error> {
@ -114,7 +122,8 @@ impl TaskContext {
extern "C" fn closure_wrapper<F: FnOnce() + Send + 'static>(closure_addr: usize) -> ! {
let closure = unsafe { Box::from_raw(closure_addr as *mut F) };
closure();
todo!("Process termination");
Process::current().exit(ExitCode::SUCCESS);
unreachable!();
}
let closure = Box::new(f);

View File

@ -3,7 +3,8 @@ use core::{arch::global_asm, fmt};
use aarch64_cpu::registers::{ELR_EL1, ESR_EL1, FAR_EL1, TTBR0_EL1, TTBR1_EL1, VBAR_EL1};
use abi::{
process::{SavedFrame, Signal, SignalEntryData},
arch::SavedFrame,
process::{Signal, SignalEntryData},
syscall::SyscallFunction,
};
use tock_registers::interfaces::{Readable, Writeable};
@ -11,10 +12,10 @@ use tock_registers::interfaces::{Readable, Writeable};
use crate::{
arch::{aarch64::cpu::Cpu, CpuMessage, PLATFORM},
debug::LogLevel,
device::{interrupt::IrqContext, platform::Platform},
device::interrupt::IrqContext,
panic::panic_secondary,
syscall::raw_syscall_handler,
task::process::Process,
task::process::{Process, TaskFrame},
};
/// Struct for register values saved when taking an exception
@ -32,9 +33,8 @@ pub struct ExceptionFrame {
// ...
}
impl ExceptionFrame {
/// Saves an userspace execution context into a frame "snapshot"
pub fn to_saved_frame(&self) -> SavedFrame {
impl TaskFrame for ExceptionFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
gp_regs: self.r,
spsr_el1: self.spsr_el1,
@ -43,12 +43,39 @@ impl ExceptionFrame {
}
}
/// Restores an userspace execution context from its frame "snapshot"
pub fn restore_from_signal(&mut self, frame: &SavedFrame) {
self.r = frame.gp_regs;
self.spsr_el1 = frame.spsr_el1;
self.elr_el1 = frame.elr_el1;
self.sp_el0 = frame.sp_el0;
fn restore(&mut self, saved: &SavedFrame) {
self.r = saved.gp_regs;
self.spsr_el1 = saved.spsr_el1;
self.elr_el1 = saved.elr_el1;
self.sp_el0 = saved.sp_el0;
}
fn argument(&self) -> u64 {
self.r[0]
}
fn user_ip(&self) -> usize {
self.elr_el1 as _
}
fn user_sp(&self) -> usize {
self.sp_el0 as _
}
fn set_argument(&mut self, value: u64) {
self.r[0] = value;
}
fn set_return_value(&mut self, value: u64) {
self.r[0] = value;
}
fn set_user_ip(&mut self, value: usize) {
self.elr_el1 = value as _;
}
fn set_user_sp(&mut self, value: usize) {
self.sp_el0 = value as _;
}
}
@ -217,7 +244,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
0b111100 => {
let proc = Process::current();
warnln!("Process #{} hit a breakpoint", proc.id());
proc.try_set_signal(Signal::Aborted).ok();
proc.raise_signal(Signal::Aborted);
}
_ => {
let iss = esr_el1 & 0x1FFFFFF;
@ -231,7 +258,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
FAR_EL1.get()
);
proc.try_set_signal(Signal::MemoryAccessViolation).ok();
proc.raise_signal(Signal::MemoryAccessViolation);
return;
}
@ -245,7 +272,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
fn irq_common() {
unsafe {
let ic = IrqContext::new();
PLATFORM.interrupt_controller().handle_pending_irqs(&ic);
PLATFORM.gic.handle_pending_irqs(&ic);
}
}
@ -258,7 +285,7 @@ unsafe fn handle_signal_exit(frame: &mut ExceptionFrame) {
saved_data.frame.sp_el0
);
frame.restore_from_signal(&saved_data.frame);
frame.restore(&saved_data.frame);
}
pub(super) fn ipi_handler(msg: Option<CpuMessage>) {

View File

@ -96,6 +96,7 @@ impl Gicd {
}
}
#[allow(dead_code)]
pub unsafe fn set_sgir(&self, target: IpiDeliveryTarget, interrupt_id: u64) {
assert_eq!(interrupt_id & !0xF, 0);
let value = match target {

View File

@ -1,14 +1,11 @@
//! ARM Generic Interrupt Controller v2 driver
use core::sync::atomic::Ordering;
use aarch64_cpu::asm::barrier;
use abi::error::Error;
use spinning_top::Spinlock;
use crate::{
arch::CpuMessage,
device::{
interrupt::{InterruptController, InterruptSource, IpiDeliveryTarget},
interrupt::{ExternalInterruptController, InterruptSource, IrqContext},
Device,
},
mem::device::{DeviceMemory, DeviceMemoryIo},
@ -17,7 +14,7 @@ use crate::{
use self::{gicc::Gicc, gicd::Gicd};
use super::{cpu::Cpu, exception::ipi_handler, smp::CPU_COUNT};
use super::{cpu::Cpu, exception::ipi_handler};
const MAX_IRQ: usize = 300;
const IPI_VECTOR: u64 = 1;
@ -82,7 +79,7 @@ impl Device for Gic {
}
}
impl InterruptController for Gic {
impl ExternalInterruptController for Gic {
type IrqNumber = IrqNumber;
fn enable_irq(&self, irq: Self::IrqNumber) -> Result<(), Error> {
@ -90,34 +87,6 @@ impl InterruptController for Gic {
Ok(())
}
fn handle_pending_irqs<'irq>(&'irq self, ic: &crate::device::interrupt::IrqContext<'irq>) {
let gicc = self.gicc.get();
let irq_number = gicc.pending_irq_number(ic);
if irq_number >= MAX_IRQ {
return;
}
gicc.clear_irq(irq_number, ic);
if irq_number as u64 == IPI_VECTOR {
// IPI received
let msg = Cpu::local().get_ipi();
ipi_handler(msg);
return;
}
{
let table = self.irq_table.lock();
match table[irq_number] {
None => panic!("No IRQ handler registered for irq{}", irq_number),
Some(handler) => {
drop(table);
handler.handle_irq().expect("IRQ handler failed");
}
}
}
}
fn register_handler(
&self,
irq: Self::IrqNumber,
@ -135,28 +104,28 @@ impl InterruptController for Gic {
Ok(())
}
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error> {
// TODO message queue insertion should be moved
match target {
IpiDeliveryTarget::AllExceptLocal => {
let local = Cpu::local_id();
for i in 0..CPU_COUNT.load(Ordering::Acquire) {
if i != local as usize {
Cpu::push_ipi_queue(i as u32, msg);
}
}
}
IpiDeliveryTarget::Specified(_) => todo!(),
}
// unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error> {
// // TODO message queue insertion should be moved
// match target {
// IpiDeliveryTarget::AllExceptLocal => {
// let local = Cpu::local_id();
// for i in 0..CPU_COUNT.load(Ordering::Acquire) {
// if i != local as usize {
// Cpu::push_ipi_queue(i as u32, msg);
// }
// }
// }
// IpiDeliveryTarget::Specified(_) => todo!(),
// }
// Issue a memory barrier
barrier::dsb(barrier::ISH);
barrier::isb(barrier::SY);
// // Issue a memory barrier
// barrier::dsb(barrier::ISH);
// barrier::isb(barrier::SY);
self.gicd.get().set_sgir(target, IPI_VECTOR);
// self.gicd.get().set_sgir(target, IPI_VECTOR);
Ok(())
}
// Ok(())
// }
}
impl Gic {
@ -184,4 +153,33 @@ impl Gic {
self.gicc.get().init();
Ok(())
}
/// Handles a single pending IRQ (if there're many, the CPU will just get here again)
pub fn handle_pending_irqs<'irq>(&'irq self, ic: &IrqContext<'irq>) {
let gicc = self.gicc.get();
let irq_number = gicc.pending_irq_number(ic);
if irq_number >= MAX_IRQ {
return;
}
gicc.clear_irq(irq_number, ic);
if irq_number as u64 == IPI_VECTOR {
// IPI received
let msg = Cpu::local().get_ipi();
ipi_handler(msg);
return;
}
{
let table = self.irq_table.lock();
match table[irq_number] {
None => panic!("No IRQ handler registered for irq{}", irq_number),
Some(handler) => {
drop(table);
handler.handle_irq().expect("IRQ handler failed");
}
}
}
}
}

View File

@ -1,13 +0,0 @@
//! Intrinsic helper functions for AArch64 platforms
/// Returns an absolute address to the given symbol
#[macro_export]
macro_rules! absolute_address {
($sym:expr) => {{
let mut _x: usize;
unsafe {
core::arch::asm!("ldr {0}, ={1}", out(reg) _x, sym $sym);
}
_x
}};
}

View File

@ -30,8 +30,6 @@ use self::{
table::{init_fixed_tables, KERNEL_TABLES},
};
pub mod intrinsics;
pub mod plat_qemu;
pub mod boot;
@ -205,7 +203,7 @@ pub fn kernel_main(dtb_phys: usize) -> ! {
AArch64::set_interrupt_mask(true);
ARCHITECTURE.init_device_tree(dtb_phys);
PLATFORM.init_primary_serial();
PLATFORM.init_primary_debug_sink();
}
// Setup debugging functions
debug::init();

View File

@ -4,11 +4,11 @@ use abi::error::Error;
use tock_registers::interfaces::Writeable;
use crate::{
debug::DebugSink,
device::{
interrupt::{InterruptController, InterruptSource},
interrupt::{ExternalInterruptController, InterruptSource},
platform::Platform,
serial::{pl011::Pl011, SerialDevice},
timer::TimestampSource,
serial::pl011::Pl011,
Device,
},
fs::devfs::{self, CharDeviceType},
@ -21,7 +21,8 @@ use super::{
/// AArch64 "virt" platform implementation
pub struct QemuPlatform {
gic: Gic,
/// ...
pub gic: Gic,
pl011: Pl011,
local_timer: ArmTimer,
}
@ -52,25 +53,39 @@ impl Platform for QemuPlatform {
Ok(())
}
unsafe fn init_primary_serial(&self) {
unsafe fn init_primary_debug_sink(&self) {
self.pl011.init().ok();
}
fn primary_debug_sink(&self) -> Option<&dyn DebugSink> {
Some(&self.pl011)
}
fn interrupt_controller(
&self,
) -> &dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
&self.gic
}
// unsafe fn init_primary_serial(&self) {
// self.pl011.init().ok();
// }
fn name(&self) -> &'static str {
"qemu"
}
fn primary_serial(&self) -> Option<&dyn SerialDevice> {
Some(&self.pl011)
}
// fn primary_serial(&self) -> Option<&dyn SerialDevice> {
// Some(&self.pl011)
// }
fn interrupt_controller(&self) -> &dyn InterruptController<IrqNumber = Self::IrqNumber> {
&self.gic
}
// fn interrupt_controller(&self) -> &dyn InterruptController<IrqNumber = Self::IrqNumber> {
// &self.gic
// }
fn timestamp_source(&self) -> &dyn TimestampSource {
&self.local_timer
}
// fn timestamp_source(&self) -> &dyn TimestampSource {
// &self.local_timer
// }
}
/// AArch64 "virt" platform

View File

@ -12,7 +12,9 @@ use tock_registers::interfaces::Readable;
use crate::mem::{
phys::{self, PageUsage},
table::{EntryLevel, NextPageTable, VirtualMemoryManager},
table::{
EntryLevel, MapAttributes, NextPageTable, NonTerminalEntryLevel, VirtualMemoryManager,
},
ConvertAddress, KERNEL_VIRT_OFFSET,
};
@ -306,12 +308,27 @@ impl FixedTables {
}
}
impl From<MapAttributes> for PageAttributes {
fn from(value: MapAttributes) -> Self {
let mut res = Self::empty();
if value.contains(MapAttributes::USER_WRITE) {
res |= PageAttributes::AP_BOTH_READWRITE;
} else {
res |= PageAttributes::AP_BOTH_READONLY;
}
if value.contains(MapAttributes::NON_GLOBAL) {
res |= PageAttributes::NON_GLOBAL;
}
res
}
}
impl VirtualMemoryManager for AddressSpace {
fn allocate(
&self,
hint: Option<usize>,
len: usize,
attrs: PageAttributes,
attrs: MapAttributes,
) -> Result<usize, Error> {
assert_eq!(DAIF.read(DAIF::I), 1);
@ -356,6 +373,10 @@ impl VirtualMemoryManager for AddressSpace {
Ok(())
}
fn map_page(&self, virt: usize, phys: usize, attrs: MapAttributes) -> Result<(), Error> {
self.write_entry(virt, PageEntry::page(phys, attrs.into()), true)
}
}
impl AddressSpace {
@ -412,11 +433,6 @@ impl AddressSpace {
Ok(())
}
/// Inserts a single 4KiB virt -> phys mapping into the address apce
pub fn map_page(&self, virt: usize, phys: usize, attrs: PageAttributes) -> Result<(), Error> {
self.write_entry(virt, PageEntry::page(phys, attrs), true)
}
/// Returns the physical address of the address space (to be used in a TTBRn_ELx)
pub fn physical_address(&self) -> usize {
unsafe { (self.l1 as usize).physicalize() | ((self.asid as usize) << 48) }

View File

@ -44,7 +44,7 @@ impl TimestampSource for ArmTimer {
}
impl InterruptSource for ArmTimer {
fn handle_irq(&self) -> Result<(), Error> {
fn handle_irq(&self) -> Result<bool, Error> {
CNTP_TVAL_EL0.set(TICK_INTERVAL);
let t = self.timestamp()?;
@ -55,7 +55,7 @@ impl InterruptSource for ArmTimer {
Cpu::local().queue().yield_cpu();
}
Ok(())
Ok(true)
}
unsafe fn init_irq(&'static self) -> Result<(), Error> {

View File

@ -3,18 +3,32 @@
use abi::error::Error;
use cfg_if::cfg_if;
/// Returns an absolute address to the given symbol
#[macro_export]
macro_rules! absolute_address {
($sym:expr) => {{
let mut _x: usize;
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("ldr {0}, ={1}", out(reg) _x, sym $sym);
}
#[cfg(target_arch = "x86_64")]
unsafe {
core::arch::asm!("movabsq ${1}, {0}", out(reg) _x, sym $sym, options(att_syntax));
}
_x
}};
}
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod aarch64;
pub use aarch64::intrinsics::absolute_address;
pub use aarch64::plat_qemu::{QemuPlatform as PlatformImpl, PLATFORM};
pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
use abi::error::Error;
use cfg_if::cfg_if;
} else if #[cfg(target_arch = "x86_64")] {
#[macro_use]
pub mod x86_64;
pub use x86_64::{

View File

@ -8,7 +8,7 @@ use crate::{
task::process::Process,
};
use super::exception::{self, ExceptionFrame, IrqFrame};
use super::exception::{self, IrqFrame};
pub mod ioapic;
pub mod local;
@ -82,15 +82,17 @@ fn apic_irq_inner(vector: u32) {
}
}
/// Main handler for APIC interrupts
pub extern "C" fn __x86_64_apic_irq_handler(vector: u32, frame: *mut IrqFrame) {
let frame = unsafe { &mut *frame };
/// Main handler for APIC interrupts.
///
/// # Safety
///
/// Only meant to be called from the assembly irq vector.
pub unsafe extern "C" fn __x86_64_apic_irq_handler(vector: u32, frame: *mut IrqFrame) {
let frame = &mut *frame;
apic_irq_inner(vector);
if let Some(process) = Process::get_current() {
unsafe {
process.handle_signal(frame);
}
}
}

View File

@ -1,7 +1,7 @@
//! x86-64 task context setup and switching
use core::{arch::global_asm, cell::UnsafeCell};
use abi::error::Error;
use abi::{error::Error, process::ExitCode};
use alloc::boxed::Box;
use crate::{
@ -10,6 +10,7 @@ use crate::{
phys::{self, PageUsage},
ConvertAddress,
},
task::process::Process,
};
struct StackBuilder {
@ -84,7 +85,9 @@ impl StackBuilder {
}
impl TaskContext {
/// Number of bytes to offset the signal stack pointer by
pub const SIGNAL_STACK_EXTRA_ALIGN: usize = 8;
/// Number of bytes to offset the user stack pointer by
pub const USER_STACK_EXTRA_ALIGN: usize = 8;
/// Constructs a kernel-space task context
@ -147,7 +150,8 @@ impl TaskContext {
extern "C" fn closure_wrapper<F: FnOnce() + Send + 'static>(closure_addr: usize) -> ! {
let closure = unsafe { Box::from_raw(closure_addr as *mut F) };
closure();
todo!("Process termination");
Process::current().exit(ExitCode::SUCCESS);
unreachable!();
}
let closure = Box::new(f);

View File

@ -1,32 +1,15 @@
//! x86-64 exception and interrupt handling
use core::{arch::global_asm, mem::size_of_val};
use abi::{
arch::SavedFrame,
primitive_enum,
process::{Signal, SignalEntryData},
syscall::SyscallFunction,
};
use tock_registers::interfaces::{ReadWriteable, Writeable};
use abi::{arch::SavedFrame, primitive_enum, process::Signal};
use crate::{
arch::{
x86_64::{
apic::{self, __x86_64_apic_irq_handler},
registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR},
},
Architecture, ArchitectureImpl,
},
mem::table::AddressSpace,
syscall::raw_syscall_handler,
task::{
process::{Process, TaskFrame},
Cpu,
},
arch::x86_64::apic::{self, __x86_64_apic_irq_handler},
task::process::{Process, TaskFrame},
};
primitive_enum! {
pub enum ExceptionKind: u64 {
enum ExceptionKind: u64 {
DivisionError = 0,
Debug = 1,
NonMaskableInterrupt = 2,
@ -53,8 +36,9 @@ primitive_enum! {
}
impl ExceptionKind {
pub fn ring3_possible(&self) -> bool {
match self {
fn ring3_possible(&self) -> bool {
matches!(
self,
Self::DivisionError
| Self::Debug
| Self::Breakpoint
@ -65,107 +49,12 @@ impl ExceptionKind {
| Self::PageFault
| Self::FpuException
| Self::AlignmentCheck
| Self::SimdFpuException => true,
_ => false,
}
}
}
impl TaskFrame for IrqFrame {
fn store(&self) -> SavedFrame {
todo!()
}
fn restore(&mut self, saved: &SavedFrame) {
todo!()
}
fn argument(&self) -> u64 {
todo!();
}
fn user_ip(&self) -> usize {
todo!()
}
fn user_sp(&self) -> usize {
todo!()
}
fn set_argument(&mut self, value: u64) {
self.rdi = value;
}
fn set_return_value(&mut self, value: u64) {
todo!()
}
fn set_user_ip(&mut self, value: usize) {
todo!()
}
fn set_user_sp(&mut self, value: usize) {
todo!()
}
}
impl TaskFrame for ExceptionFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
rax: self.rax,
rcx: self.rcx,
rdx: self.rdx,
rbx: self.rbx,
rsi: self.rsi,
rdi: self.rdi,
rbp: self.rbp,
r8: self.r8,
r9: self.r9,
r10: self.r10,
r11: self.r11,
r12: self.r12,
r13: self.r13,
r14: self.r14,
r15: self.r15,
user_ip: self.rip,
user_sp: self.rsp,
rflags: self.rflags,
}
}
fn restore(&mut self, saved: &SavedFrame) {
todo!()
}
fn argument(&self) -> u64 {
0
}
fn user_sp(&self) -> usize {
self.rsp as _
}
fn user_ip(&self) -> usize {
self.rip as _
}
fn set_user_sp(&mut self, value: usize) {
self.rsp = value as _;
}
fn set_user_ip(&mut self, value: usize) {
self.rip = value as _;
}
fn set_return_value(&mut self, _value: u64) {
// Not in syscall, do not overwrite
}
fn set_argument(&mut self, value: u64) {
self.rdi = value;
| Self::SimdFpuException
)
}
}
/// Frame saved onto the stack when taking an IRQ
#[derive(Debug)]
#[repr(C)]
pub struct IrqFrame {
@ -243,6 +132,101 @@ struct Pointer {
offset: usize,
}
impl TaskFrame for IrqFrame {
fn store(&self) -> SavedFrame {
todo!()
}
fn restore(&mut self, _saved: &SavedFrame) {
todo!()
}
fn argument(&self) -> u64 {
todo!();
}
fn user_ip(&self) -> usize {
todo!()
}
fn user_sp(&self) -> usize {
todo!()
}
fn set_argument(&mut self, value: u64) {
self.rdi = value;
}
fn set_return_value(&mut self, _value: u64) {
todo!()
}
fn set_user_ip(&mut self, _value: usize) {
todo!()
}
fn set_user_sp(&mut self, _value: usize) {
todo!()
}
}
impl TaskFrame for ExceptionFrame {
fn store(&self) -> SavedFrame {
SavedFrame {
rax: self.rax,
rcx: self.rcx,
rdx: self.rdx,
rbx: self.rbx,
rsi: self.rsi,
rdi: self.rdi,
rbp: self.rbp,
r8: self.r8,
r9: self.r9,
r10: self.r10,
r11: self.r11,
r12: self.r12,
r13: self.r13,
r14: self.r14,
r15: self.r15,
user_ip: self.rip,
user_sp: self.rsp,
rflags: self.rflags,
}
}
fn restore(&mut self, _saved: &SavedFrame) {
todo!()
}
fn argument(&self) -> u64 {
0
}
fn user_sp(&self) -> usize {
self.rsp as _
}
fn user_ip(&self) -> usize {
self.rip as _
}
fn set_user_sp(&mut self, value: usize) {
self.rsp = value as _;
}
fn set_user_ip(&mut self, value: usize) {
self.rip = value as _;
}
fn set_return_value(&mut self, _value: u64) {
// Not in syscall, do not overwrite
}
fn set_argument(&mut self, value: u64) {
self.rdi = value;
}
}
const SIZE: usize = 256;
impl Entry {
@ -278,7 +262,7 @@ impl Entry {
static mut IDT: [Entry; SIZE] = [Entry::NULL; SIZE];
fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
fn user_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) {
let process = Process::current();
warnln!("{:?} in #{} {:?}", kind, process.id(), process.name());
@ -295,42 +279,15 @@ fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
warnln!("CR2 = {:#x}", cr2);
process.raise_signal(Signal::MemoryAccessViolation);
return;
}
ExceptionKind::InvalidOpcode => {
process.raise_signal(Signal::Aborted);
return;
}
_ => todo!("No handler for exception: {:?}", kind),
}
// errorln!("Exception {}", frame.exc_number);
// errorln!("CS:RIP = {:#x}:{:#x}", frame.cs, frame.rip);
// errorln!("SS:RSP = {:#x}:{:#x}", frame.ss, frame.rsp);
// if let Some(cpu) = Cpu::get_local() {
// let current = cpu.queue().current_process();
// if let Some(current) = current {
// errorln!("In process #{} {:?}", current.id(), current.name());
// }
// }
// debugln!("Registers:\n{:#x?}", &frame);
// if frame.exc_number == 6 {
// // Invalid opcode
// warnln!("Invalid opcode");
// }
// if frame.exc_number == 14 {
// }
// loop {
// ArchitectureImpl::wait_for_interrupt();
// }
}
fn kernel_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) -> ! {
fn kernel_exception_inner(_kind: ExceptionKind, _frame: &ExceptionFrame) -> ! {
todo!()
}
@ -349,18 +306,6 @@ extern "C" fn __x86_64_exception_handler(frame: *mut ExceptionFrame) {
}
}
pub unsafe fn handle_signal_exit<F: TaskFrame>(frame: &mut F) {
// TODO validate the argument
let saved_data = &*(frame.argument() as *const SignalEntryData);
infoln!(
"Handling signal exit to ip={:#x}, sp={:#x}",
saved_data.frame.user_ip,
saved_data.frame.user_sp
);
frame.restore(&saved_data.frame);
}
/// Initializes the interrupt descriptor table for the given CPU.
///
/// # Safety

View File

@ -2,18 +2,6 @@
use core::marker::PhantomData;
/// Returns an absolute address to the given symbol
#[macro_export]
macro_rules! absolute_address {
($sym:expr) => {{
let mut _x: usize;
unsafe {
core::arch::asm!("movabsq ${1}, {0}", out(reg) _x, sym $sym, options(att_syntax));
}
_x
}};
}
/// Wrapper struct providing access to an x86 I/O port
#[derive(Clone, Debug)]
#[repr(transparent)]

View File

@ -76,10 +76,10 @@ impl InterruptSource for PS2Controller {
return Ok(false);
}
let mut key = self.data.read();
let key = self.data.read();
if key == 0xE0 {
key = self.data.read();
self.data.read();
infoln!("TODO: handle 0xE0");
return Ok(true);
}

View File

@ -1,6 +1,8 @@
//! x86-64 implementation of system call interface
use core::arch::global_asm;
use abi::{arch::SavedFrame, syscall::SyscallFunction};
use abi::{arch::SavedFrame, process::SignalEntryData, syscall::SyscallFunction};
use tock_registers::interfaces::{ReadWriteable, Writeable};
use crate::{
@ -9,12 +11,10 @@ use crate::{
task::process::{Process, TaskFrame},
};
use super::exception::handle_signal_exit;
/// Set of registers saved when taking a syscall instruction
#[derive(Debug)]
#[repr(C)]
pub struct SyscallFrame {
struct SyscallFrame {
rax: u64,
args: [u64; 6],
@ -132,6 +132,23 @@ extern "C" fn __x86_64_syscall_handler(frame: *mut SyscallFrame) {
}
}
unsafe fn handle_signal_exit<F: TaskFrame>(frame: &mut F) {
// TODO validate the argument
let saved_data = &*(frame.argument() as *const SignalEntryData);
infoln!(
"Handling signal exit to ip={:#x}, sp={:#x}",
saved_data.frame.user_ip,
saved_data.frame.user_sp
);
frame.restore(&saved_data.frame);
}
/// Initializes system call instruction support for the current CPU.
///
/// # Safety
///
/// Only meant to be called once per each CPU during their init.
pub unsafe fn init_syscall() {
extern "C" {
fn __x86_64_syscall_vector();

View File

@ -182,6 +182,7 @@ impl<L: EntryLevel> PageEntry<L> {
/// An entry that is not mapped
pub const INVALID: Self = Self(0, PhantomData);
/// Returns `true` if the entry contains a valid mapping to either a table or to a page/block
pub fn is_present(&self) -> bool {
self.0 & PageAttributes::PRESENT.bits() != 0
}
@ -252,12 +253,6 @@ impl<L: EntryLevel> IndexMut<usize> for PageTable<L> {
}
}
impl From<PageAttributes> for MapAttributes {
fn from(value: PageAttributes) -> Self {
todo!();
}
}
impl From<MapAttributes> for PageAttributes {
fn from(value: MapAttributes) -> Self {
let mut res = PageAttributes::WRITABLE;
@ -337,12 +332,6 @@ impl AddressSpace {
Ok(Self { l0 })
}
pub unsafe fn from_cr3(cr3: usize) -> Self {
let cr3_virt = cr3.virtualize();
let l0 = unsafe { cr3_virt as *mut PageTable<L0> };
Self { l0 }
}
unsafe fn as_mut(&self) -> &'static mut PageTable<L0> {
self.l0.as_mut().unwrap()
}

View File

@ -3,7 +3,12 @@ use core::fmt::{self, Arguments};
use abi::error::Error;
use crate::{arch::PLATFORM, device::platform::Platform, sync::IrqSafeSpinlock, util::OneTimeInit};
use crate::{
arch::PLATFORM,
device::{platform::Platform, serial::SerialDevice},
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
// use crate::{
// arch::PLATFORM,
@ -46,6 +51,12 @@ pub trait DebugSink {
}
}
impl<T: SerialDevice> DebugSink for T {
fn putc(&self, c: u8) -> Result<(), Error> {
self.send(c)
}
}
struct DebugPrinter {
sink: &'static dyn DebugSink,
}

View File

@ -1,5 +1,10 @@
//! Input device interfaces
use super::{tty::TtyDevice, Device};
/// Generic keyboard-like input device interface
pub trait KeyboardDevice: Device {
/// Indicates to the keyboard driver that it was attached to a terminal so it knows where to
/// send its input data to
fn attach(&self, terminal: &'static dyn TtyDevice<16>);
}

View File

@ -151,7 +151,7 @@ impl InterruptSource for Pl011 {
Ok(())
}
fn handle_irq(&self) -> Result<(), Error> {
fn handle_irq(&self) -> Result<bool, Error> {
let inner = self.inner.get().lock();
inner.regs.ICR.write(ICR::ALL::CLEAR);
@ -160,7 +160,7 @@ impl InterruptSource for Pl011 {
self.recv_byte(byte as u8);
Ok(())
Ok(true)
}
}

View File

@ -19,14 +19,18 @@ use crate::{
use super::{input::KeyboardDevice, serial::SerialDevice, Device};
// TODO rewrite this
/// Helper device to combine a display and a keyboard input into a single terminal
pub struct CombinedTerminal {
#[allow(dead_code)]
input: &'static dyn KeyboardDevice,
output: &'static FramebufferConsole,
// TODO output
input_ring: CharRing<16>,
}
impl CombinedTerminal {
/// Create a combined terminal device from a keyboard and console output devices
pub fn new(input: &'static dyn KeyboardDevice, output: &'static FramebufferConsole) -> Self {
Self {
input,
@ -43,7 +47,7 @@ impl TtyDevice<16> for CombinedTerminal {
}
impl SerialDevice for CombinedTerminal {
fn receive(&self, blocking: bool) -> Result<u8, Error> {
fn receive(&self, _blocking: bool) -> Result<u8, Error> {
todo!()
}

View File

@ -19,25 +19,13 @@
use abi::{
error::Error,
io::{FileMode, OpenOptions, RawFd},
process::ExitCode,
};
use fs::{devfs, FileBlockAllocator, INITRD_DATA};
use memfs::MemoryFilesystem;
use task::process::Process;
use vfs::{Filesystem, IoContext, VnodeRef};
extern crate yggdrasil_abi as abi;
//
// use abi::{
// error::Error,
// io::{FileMode, OpenOptions, RawFd},
// process::ExitCode,
// };
// use fs::{devfs, FileBlockAllocator, INITRD_DATA};
// use memfs::MemoryFilesystem;
// use task::process::Process;
// use vfs::{Filesystem, IoContext, VnodeRef};
//
extern crate alloc;
#[macro_use]
@ -94,7 +82,12 @@ pub fn kernel_main() {
let file = node.open(OpenOptions::READ, FileMode::empty()).unwrap();
let devfs = devfs::root();
#[cfg(target_arch = "x86_64")]
let console = ioctx.find(Some(devfs.clone()), "tty0", true, true).unwrap();
#[cfg(target_arch = "aarch64")]
let console = ioctx
.find(Some(devfs.clone()), "ttyS0", true, true)
.unwrap();
let stdin = console.open(OpenOptions::READ, FileMode::empty()).unwrap();
let stdout = console.open(OpenOptions::WRITE, FileMode::empty()).unwrap();
let stderr = stdout.clone();
@ -112,8 +105,4 @@ pub fn kernel_main() {
user_init.enqueue_somewhere();
}
loop {}
// XXX
// Process::current().exit(ExitCode::SUCCESS);
}

View File

@ -12,10 +12,14 @@ cfg_if! {
}
bitflags! {
/// Describes how a page translation mapping should behave
#[derive(Clone, Copy)]
pub struct MapAttributes: u64 {
/// The data mapped can be read by the user process
const USER_READ = 1 << 0;
/// The data mapped can be written to by the user process
const USER_WRITE = 1 << 1;
/// The mapping is not global across the address spaces
const NON_GLOBAL = 1 << 2;
}
}
@ -31,6 +35,7 @@ pub trait VirtualMemoryManager {
attrs: MapAttributes,
) -> Result<usize, Error>;
/// Insert a single 4KiB-page translation mapping into the table
fn map_page(&self, virt: usize, phys: usize, attrs: MapAttributes) -> Result<(), Error>;
/// Releases the virtual memory region from the address space and the pages it refers to

View File

@ -106,6 +106,8 @@ fn setup_binary<S: Into<String>>(
// Fill with some sentinel value to detect stack underflows
let ptr = user_sp as *mut u64;
#[allow(clippy::reversed_empty_ranges)]
for i in 0..TaskContext::USER_STACK_EXTRA_ALIGN / 8 {
unsafe {
ptr.add(i).write_foreign_volatile(&space, 0xDEADC0DE);

View File

@ -5,8 +5,6 @@ use abi::error::Error;
use alloc::{collections::LinkedList, rc::Rc};
use crate::{
arch::PLATFORM,
device::platform::Platform,
sync::IrqSafeSpinlock,
task::process::{Process, ProcessState},
};
@ -32,6 +30,7 @@ pub struct Wait {
struct Timeout {
process: Rc<Process>,
#[allow(dead_code)]
deadline: Duration,
}
@ -122,7 +121,7 @@ impl Wait {
queue_lock = self.queue.lock();
if let Some(deadline) = deadline {
if let Some(_deadline) = deadline {
// let now = PLATFORM.timestamp_source().timestamp()?;
// if now > deadline {
@ -147,7 +146,7 @@ impl Wait {
static TICK_LIST: IrqSafeSpinlock<LinkedList<Timeout>> = IrqSafeSpinlock::new(LinkedList::new());
/// Suspends current task until given deadline
pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Error> {
pub fn sleep(_timeout: Duration, _remaining: &mut Duration) -> Result<(), Error> {
todo!();
// static SLEEP_NOTIFY: Wait = Wait::new("sleep");
// let now = PLATFORM.timestamp_source().timestamp()?;
@ -166,8 +165,7 @@ pub fn sleep(timeout: Duration, remaining: &mut Duration) -> Result<(), Error> {
}
/// Updates all pending timeouts and wakes up the tasks that have reached theirs
pub fn tick(now: Duration) {
todo!();
pub fn tick(_now: Duration) {
// let mut list = TICK_LIST.lock();
// let mut cursor = list.cursor_front_mut();

View File

@ -20,7 +20,7 @@ use crate::{
proc::{
self,
io::ProcessIo,
wait::PROCESS_EXIT_WAIT,
wait::{self, PROCESS_EXIT_WAIT},
// wait::{self, PROCESS_EXIT_WAIT},
},
sync::IrqSafeSpinlockGuard,
@ -63,15 +63,14 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
Ok(0)
}
SyscallFunction::Nanosleep => {
todo!();
// let seconds = args[0];
// let nanos = args[1] as u32;
// let duration = Duration::new(seconds, nanos);
// let mut remaining = Duration::ZERO;
let seconds = args[0];
let nanos = args[1] as u32;
let duration = Duration::new(seconds, nanos);
let mut remaining = Duration::ZERO;
// wait::sleep(duration, &mut remaining).unwrap();
wait::sleep(duration, &mut remaining).unwrap();
// Ok(0)
Ok(0)
}
SyscallFunction::Exit => {
let code = ExitCode::from(args[0] as i32);
@ -142,11 +141,11 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
debugln!("run_with_io_at {:?}", at);
let file = io.ioctx().open(at, path, opts, mode)?;
// if proc.session_terminal().is_none() &&
// let Ok(node) = file.borrow().node() && node.kind() == VnodeKind::Char {
// debugln!("Session terminal set for #{}: {}", proc.id(), path);
// proc.set_session_terminal(node);
// }
if proc.session_terminal().is_none() &&
let Ok(node) = file.borrow().node() && node.kind() == VnodeKind::Char {
debugln!("Session terminal set for #{}: {}", proc.id(), path);
proc.set_session_terminal(node);
}
let fd = io.place_file(file)?;
Ok(fd.0 as usize)
@ -179,17 +178,16 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
})
}
SyscallFunction::Unmount => {
todo!();
// let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
let options = arg_user_ref::<UnmountOptions>(args[0] as usize)?;
// run_with_io(|mut io| {
// let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
// mountpoint.unmount_target()?;
run_with_io(|mut io| {
let mountpoint = io.ioctx().find(None, options.mountpoint, true, false)?;
mountpoint.unmount_target()?;
// debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
debugln!("{:?}", vfs::VnodeDump::new(io.ioctx().root().clone()));
// Ok(0)
// })
Ok(0)
})
}
SyscallFunction::OpenDirectory => {
let at = arg_option_fd(args[0] as u32);
@ -218,70 +216,66 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
})
}
SyscallFunction::CreateDirectory => {
todo!();
// let at = arg_option_fd(args[0] as u32);
// let path = arg_user_str(args[1] as usize, args[2] as usize)?;
// let _mode = FileMode::from(args[3] as u32);
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let _mode = FileMode::from(args[3] as u32);
// run_with_io_at(at, |at, mut io| {
// let (parent, name) = abi::path::split_right(path);
// let parent_node = io.ioctx().find(at, parent, true, true)?;
// parent_node.create(name, VnodeKind::Directory)?;
run_with_io_at(at, |at, mut io| {
let (parent, name) = abi::path::split_right(path);
let parent_node = io.ioctx().find(at, parent, true, true)?;
parent_node.create(name, VnodeKind::Directory)?;
// Ok(0)
// })
Ok(0)
})
}
SyscallFunction::Remove => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let recurse = args[3] != 0;
run_with_io_at(at, |at, mut io| {
let node = io.ioctx().find(at, path, false, false)?;
if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
todo!();
// let at = arg_option_fd(args[0] as u32);
// let path = arg_user_str(args[1] as usize, args[2] as usize)?;
// let recurse = args[3] != 0;
}
// run_with_io_at(at, |at, mut io| {
// let node = io.ioctx().find(at, path, false, false)?;
let parent = node.parent();
// if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
// todo!();
// }
parent.remove(node, recurse)?;
// let parent = node.parent();
// parent.remove(node, recurse)?;
// Ok(0)
// })
Ok(0)
})
}
SyscallFunction::GetMetadata => {
todo!();
// let at = arg_option_fd(args[0] as u32);
// let path = arg_user_str(args[1] as usize, args[2] as usize)?;
// let buffer = arg_user_mut::<MaybeUninit<FileAttr>>(args[3] as usize)?;
// let follow = args[4] != 0;
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let buffer = arg_user_mut::<MaybeUninit<FileAttr>>(args[3] as usize)?;
let follow = args[4] != 0;
// run_with_io_at(at, |at, mut io| {
// let node = if path.is_empty() {
// at.ok_or(Error::InvalidArgument)?
// } else {
// io.ioctx().find(None, path, follow, true)?
// };
run_with_io_at(at, |at, mut io| {
let node = if path.is_empty() {
at.ok_or(Error::InvalidArgument)?
} else {
io.ioctx().find(None, path, follow, true)?
};
// let metadata = node.metadata()?;
// buffer.write(metadata);
let metadata = node.metadata()?;
buffer.write(metadata);
// Ok(0)
// })
Ok(0)
})
}
SyscallFunction::Seek => {
todo!();
// let fd = RawFd(args[0] as u32);
// let pos = SeekFrom::from(args[1]);
let fd = RawFd(args[0] as u32);
let pos = SeekFrom::from(args[1]);
// run_with_io(|io| {
// let file = io.file(fd)?;
// let mut file_borrow = file.borrow_mut();
run_with_io(|io| {
let file = io.file(fd)?;
let mut file_borrow = file.borrow_mut();
// file_borrow.seek(pos).map(|v| v as usize)
// })
file_borrow.seek(pos).map(|v| v as usize)
})
}
SyscallFunction::Spawn => {
let options = arg_user_ref::<SpawnOptions>(args[0] as usize)?;
@ -342,14 +336,13 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
}
}
SyscallFunction::SendSignal => {
todo!();
// let pid = args[0] as u32;
// let signal = Signal::try_from(args[1] as u32).map_err(|_| Error::InvalidArgument)?;
let pid = args[0] as u32;
let signal = Signal::try_from(args[1] as u32).map_err(|_| Error::InvalidArgument)?;
// let target = Process::get(pid as _).ok_or(Error::DoesNotExist)?;
// target.try_set_signal(signal)?;
let target = Process::get(pid as _).ok_or(Error::DoesNotExist)?;
target.raise_signal(signal);
// Ok(0)
Ok(0)
}
SyscallFunction::SetSignalEntry => {
let entry = args[0] as usize;

View File

@ -16,13 +16,6 @@ cfg_if! {
use crate::{
kernel_main,
mem::{
phys::{self, PageUsage},
table::AddressSpace,
ConvertAddress,
},
//arch::aarch64::{context::TaskContext, cpu::Cpu, smp::CPU_COUNT},
// kernel_main,
sync::{IrqSafeSpinlock, SpinFence},
task::sched::CpuQueue,
};

View File

@ -26,17 +26,33 @@ use crate::{
use super::{sched::CpuQueue, Cpu, ProcessId, TaskContext, PROCESSES};
/// Interface for task state save/restore mechanisms
pub trait TaskFrame {
/// Creates a "snapshot" of a exception/syscall frame
fn store(&self) -> SavedFrame;
/// Restores the exception/syscall frame from its saved state
fn restore(&mut self, saved: &SavedFrame);
/// Replaces the return value in the frame (or does nothing, if the frame is not a part of a
/// syscall signal handler)
fn set_return_value(&mut self, value: u64);
/// Replaces the userspace stack pointer in the frame
fn set_user_sp(&mut self, value: usize);
/// Replaces the userspace instruction pointer in the frame
fn set_user_ip(&mut self, value: usize);
/// Replaces the argument in the frame
fn set_argument(&mut self, value: u64);
/// Returns the argument (if any) of the frame being processed
fn argument(&self) -> u64;
/// Returns the userspace stack pointer
fn user_sp(&self) -> usize;
/// Returns the userspace instruction pointer
fn user_ip(&self) -> usize;
}
@ -149,6 +165,7 @@ impl Process {
*self.id.get()
}
/// Returns the binary name of the process
pub fn name(&self) -> &str {
self.name.as_str()
}
@ -187,7 +204,6 @@ impl Process {
self.space.as_ref()
}
// XXX
/// Replaces the task's session terminal device with another one
pub fn set_session_terminal(&self, terminal: VnodeRef) {
self.inner.lock().session_terminal.replace(terminal);
@ -324,7 +340,7 @@ impl Process {
Self::get_current().unwrap()
}
// /// Handles the cleanup of an exited process
/// Handles the cleanup of an exited process
pub fn handle_exit(&self) {
// Queue lock is still held
assert_eq!(self.state(), ProcessState::Terminated);

View File

@ -139,7 +139,9 @@ impl CpuQueue {
/// The function is only meant to be called from kernel threads (e.g. if they want to yield
/// CPU execution to wait for something) or interrupt handlers.
pub unsafe fn yield_cpu(&self) {
assert!(ArchitectureImpl::interrupt_mask());
// Make sure the scheduling process doesn't get interrupted
ArchitectureImpl::set_interrupt_mask(true);
let mut inner = self.inner.lock();
// let t = CNTPCT_EL0.get();