From b9c1b15bd1f41bfb99047a7ea7a92ed7835ebc64 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sat, 27 Jul 2024 14:37:46 +0300 Subject: [PATCH] kernel: fix some TODOs --- kernel/arch/x86_64/src/mem/table.rs | 5 + kernel/src/arch/aarch64/boot/entry.S | 3 +- kernel/src/arch/aarch64/boot/mod.rs | 19 +-- kernel/src/arch/aarch64/exception.rs | 58 +++---- kernel/src/arch/aarch64/gic/gicd.rs | 9 +- kernel/src/arch/aarch64/gic/mod.rs | 21 ++- kernel/src/arch/aarch64/mod.rs | 14 +- kernel/src/arch/aarch64/smp.rs | 11 +- kernel/src/arch/aarch64/vectors.S | 3 +- kernel/src/arch/x86_64/apic/ioapic.rs | 5 - kernel/src/arch/x86_64/boot/mod.rs | 1 - kernel/src/arch/x86_64/exception.rs | 47 ------ kernel/src/arch/x86_64/mod.rs | 2 - kernel/src/arch/x86_64/smp.rs | 3 +- kernel/src/arch/x86_64/syscall.S | 14 +- kernel/src/arch/x86_64/syscall.rs | 19 +-- kernel/src/device/power/sunxi_rwdog.rs | 108 ------------- kernel/src/device/serial/sunxi_uart.rs | 206 ------------------------- kernel/src/fs/mod.rs | 5 +- kernel/src/init.rs | 3 +- kernel/src/syscall/arg.rs | 16 +- kernel/src/syscall/imp/sys_process.rs | 24 +-- kernel/src/syscall/mod.rs | 22 ++- kernel/src/util/mod.rs | 23 +++ lib/abi/src/net/types/net_value.rs | 4 +- lib/qemu/src/lib.rs | 6 + xtask/src/qemu.rs | 15 +- 27 files changed, 188 insertions(+), 478 deletions(-) delete mode 100644 kernel/src/device/power/sunxi_rwdog.rs delete mode 100644 kernel/src/device/serial/sunxi_uart.rs diff --git a/kernel/arch/x86_64/src/mem/table.rs b/kernel/arch/x86_64/src/mem/table.rs index 0ece8310..efa21217 100644 --- a/kernel/arch/x86_64/src/mem/table.rs +++ b/kernel/arch/x86_64/src/mem/table.rs @@ -213,6 +213,11 @@ impl PageTable { Ok(table) } + pub unsafe fn free(this: PhysicalRefMut) { + let physical = this.as_physical_address(); + TA::free_page_table(physical); + } + // /// Returns the physical address of this table // pub fn physical_address(&self) -> usize { // unsafe { (self.data.as_ptr() as usize).physicalize() } diff --git a/kernel/src/arch/aarch64/boot/entry.S b/kernel/src/arch/aarch64/boot/entry.S index c41548c7..db21f2e2 100644 --- a/kernel/src/arch/aarch64/boot/entry.S +++ b/kernel/src/arch/aarch64/boot/entry.S @@ -106,6 +106,7 @@ __aarch64_ap_entry: isb mov sp, x0 - bl {kernel_ap_lower_entry} - {kernel_virt_offset} + MOV_ABS x0, {kernel_ap_lower_entry} - {kernel_virt_offset} + blr x0 b . diff --git a/kernel/src/arch/aarch64/boot/mod.rs b/kernel/src/arch/aarch64/boot/mod.rs index 8d3650b9..ee1a7370 100644 --- a/kernel/src/arch/aarch64/boot/mod.rs +++ b/kernel/src/arch/aarch64/boot/mod.rs @@ -16,8 +16,12 @@ use libk_mm::{ }; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; -use super::{exception, BootStack, BOOT_STACK_SIZE, PLATFORM}; -use crate::{arch::L3, kernel_main, kernel_secondary_main, mem::KERNEL_VIRT_OFFSET}; +use super::{exception, BootStack, PLATFORM}; +use crate::{ + arch::{aarch64::BOOT_STACK_SIZE, L3}, + kernel_main, kernel_secondary_main, + mem::KERNEL_VIRT_OFFSET, +}; unsafe fn pre_init_mmu() { if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran4::Supported) { @@ -51,7 +55,7 @@ unsafe fn enable_mmu() { SCTLR_EL1.modify( // Enable translation SCTLR_EL1::M::Enable + - // (TODO) Disable I + D caches + // NOTE if anything breaks due to caching, find out :) SCTLR_EL1::I::NonCacheable + SCTLR_EL1::C::NonCacheable, ); @@ -81,11 +85,10 @@ unsafe extern "C" fn __aarch64_el1_bsp_lower_entry(dtb: PhysicalAddress) -> ! { kernel_arch_aarch64::mem::load_fixed_tables(); enable_mmu(); - // Safety: SP points to the .bss section, so it's +offset mapped - let sp = unsafe { BSP_STACK.data.as_ptr().add(BOOT_STACK_SIZE) as usize } + KERNEL_VIRT_OFFSET; + // SP points to the .bss section, so it's +offset mapped + let sp = BSP_STACK.top_addr() + KERNEL_VIRT_OFFSET; let elr = absolute_address!(__aarch64_bsp_upper_entry); - // TODO pass dtb enter_higher_half(sp, elr, dtb.into_usize()); } @@ -154,9 +157,7 @@ extern "C" fn __aarch64_ap_upper_entry() -> ! { } #[link_section = ".bss"] -static BSP_STACK: BootStack = BootStack { - data: [0; BOOT_STACK_SIZE], -}; +static BSP_STACK: BootStack = BootStack::zeroed(); global_asm!( include_str!("entry.S"), diff --git a/kernel/src/arch/aarch64/exception.rs b/kernel/src/arch/aarch64/exception.rs index 048c2479..16ffa5c0 100644 --- a/kernel/src/arch/aarch64/exception.rs +++ b/kernel/src/arch/aarch64/exception.rs @@ -9,16 +9,16 @@ use aarch64_cpu::{ VBAR_EL1, }, }; -use abi::{ - process::{Signal, SignalEntryData}, - SyscallFunction, -}; -use kernel_arch::{task::TaskFrame, Architecture, ArchitectureImpl}; +use abi::{process::Signal, SyscallFunction}; +use kernel_arch::{Architecture, ArchitectureImpl}; use kernel_arch_aarch64::context::ExceptionFrame; -use libk::{device::external_interrupt_controller, task::thread::Thread}; +use libk::{arch::Cpu, device::external_interrupt_controller, task::thread::Thread}; use tock_registers::interfaces::{Readable, Writeable}; -use crate::{debug::LogLevel, syscall::raw_syscall_handler}; +use crate::{ + debug::LogLevel, + syscall::{self, raw_syscall_handler}, +}; /// Initializes the exception/interrupt vectors. May be called repeatedly (though that makes no /// sense). @@ -32,7 +32,7 @@ pub fn init_exceptions() { } fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) { - // let cpu = Cpu::get_local(); + let cpu = Cpu::try_local(); log_print_raw!(LogLevel::Fatal, "SYNC exception:\n"); log_print_raw!(LogLevel::Fatal, "FAR: {:#x}\n", FAR_EL1.get()); @@ -43,14 +43,14 @@ fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) { log_print_raw!(LogLevel::Fatal, "Register dump:\n"); log_print_raw!(LogLevel::Fatal, "{:?}\n", frame); - // XXX - // if let Some(cpu) = cpu { - // let current = cpu.queue().current_process(); + if let Some(cpu) = cpu { + // let current = cpu.queue().current_process(); + let current = cpu.current_thread_id().and_then(Thread::get); - // if let Some(current) = current { - // log_print_raw!(LogLevel::Fatal, "In process {}\n", current.id()); - // } - // } + if let Some(current) = current { + log_print_raw!(LogLevel::Fatal, "In thread {}\n", current.id); + } + } match ec { // Data abort from lower level @@ -177,7 +177,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) { let func = frame.r[8]; if func == usize::from(SyscallFunction::ExitSignal) as u64 { unsafe { - handle_signal_exit(frame); + syscall::handle_signal_exit(frame); } return; } @@ -226,16 +226,20 @@ fn irq_common() { external_interrupt_controller().handle_pending_irqs(); } -unsafe fn handle_signal_exit(frame: &mut ExceptionFrame) { - // TODO validate the argument - let saved_data = &*(frame.r[0] as *const SignalEntryData); - debugln!( - "Handling signal exit to pc={:#x}, sp={:#x}", - saved_data.frame.elr_el1, - saved_data.frame.sp_el0 - ); - - frame.restore(&saved_data.frame); -} +// unsafe fn handle_signal_exit(frame: &mut ExceptionFrame) { +// let saved_data: &SignalEntryData = match syscall::arg::ref_const(frame.r[0] as _) { +// Ok(r) => r, +// Err(err) => { +// todo!("Invalid SignalEntryData pointer: {:?}", err) +// } +// }; +// debugln!( +// "Handling signal exit to pc={:#x}, sp={:#x}", +// saved_data.frame.elr_el1, +// saved_data.frame.sp_el0 +// ); +// +// frame.restore(&saved_data.frame); +// } global_asm!(include_str!("vectors.S")); diff --git a/kernel/src/arch/aarch64/gic/gicd.rs b/kernel/src/arch/aarch64/gic/gicd.rs index 5b48ec21..94d20246 100644 --- a/kernel/src/arch/aarch64/gic/gicd.rs +++ b/kernel/src/arch/aarch64/gic/gicd.rs @@ -99,11 +99,11 @@ impl Gicd { assert_eq!(interrupt_id & !0xF, 0); let value = match target { IpiDeliveryTarget::OtherCpus => SGIR::TargetListFilter::AllExceptLocal, - IpiDeliveryTarget::Specific(_mask) => { - // TODO: need to handle self-ipi case, releasing the lock somehow - todo!(); + IpiDeliveryTarget::Specific(mask) => { + assert_eq!(mask & !0xFFFF, 0); + SGIR::TargetListFilter::SpecifiedOnly + SGIR::CPUTargetList.val(mask as _) } - IpiDeliveryTarget::ThisCpu => todo!(), + IpiDeliveryTarget::ThisCpu => SGIR::TargetListFilter::LocalOnly, } + SGIR::INTID.val(interrupt_id as u32); self.shared_regs.lock().SGIR.write(value); @@ -114,7 +114,6 @@ impl Gicd { } pub fn configure_irq(&self, irq: usize, options: IrqOptions) { - // TODO configure trigger level // 2 bits per IRQ, 16 entries per register let reg = irq / 16; let shift = (irq % 16) * 2; diff --git a/kernel/src/arch/aarch64/gic/mod.rs b/kernel/src/arch/aarch64/gic/mod.rs index 003531fd..3759672a 100644 --- a/kernel/src/arch/aarch64/gic/mod.rs +++ b/kernel/src/arch/aarch64/gic/mod.rs @@ -163,18 +163,17 @@ impl MessageInterruptController for Gic { impl LocalInterruptController for Gic { fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> { - // TODO message queue insertion should be moved - match target { - IpiDeliveryTarget::OtherCpus => { - let local = cpu_index(); - for i in 0..CPU_COUNT.load(Ordering::Acquire) { - if i != local as usize { - Cpu::push_ipi_queue(i as u32, msg); - } - } - } - IpiDeliveryTarget::Specific(_) => todo!(), + let local = cpu_index(); + let mask = match target { + IpiDeliveryTarget::OtherCpus => usize::MAX & !(1 << local), + IpiDeliveryTarget::Specific(mask) => mask, IpiDeliveryTarget::ThisCpu => todo!(), + }; + + for i in 0..CPU_COUNT.load(Ordering::Acquire) { + if mask & (1 << i) != 0 { + Cpu::push_ipi_queue(i as _, msg); + } } // Issue a memory barrier diff --git a/kernel/src/arch/aarch64/mod.rs b/kernel/src/arch/aarch64/mod.rs index e9659b7b..ff586a8f 100644 --- a/kernel/src/arch/aarch64/mod.rs +++ b/kernel/src/arch/aarch64/mod.rs @@ -49,8 +49,8 @@ const BOOT_STACK_SIZE: usize = 4096 * 32; #[derive(Clone, Copy)] #[repr(C, align(0x20))] -struct BootStack { - data: [u8; BOOT_STACK_SIZE], +struct BootStack { + data: [u8; SIZE], } /// AArch64 architecture implementation @@ -64,6 +64,16 @@ pub struct AArch64 { initrd: OneTimeInit>, } +impl BootStack { + pub const fn zeroed() -> Self { + Self { data: [0; SIZE] } + } + + pub fn top_addr(&self) -> usize { + unsafe { self.data.as_ptr().add(SIZE).addr() } + } +} + impl Platform for AArch64 { const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000; diff --git a/kernel/src/arch/aarch64/smp.rs b/kernel/src/arch/aarch64/smp.rs index cf49dfe2..e7e89659 100644 --- a/kernel/src/arch/aarch64/smp.rs +++ b/kernel/src/arch/aarch64/smp.rs @@ -11,6 +11,9 @@ use crate::mem::KERNEL_VIRT_OFFSET; use super::{BootStack, BOOT_STACK_SIZE}; +#[link_section = ".bss"] +static AP_TRAMPOLINE_STACK: BootStack = BootStack::zeroed(); + #[derive(Debug)] enum CpuEnableMethod { Psci, @@ -66,12 +69,6 @@ impl CpuEnableMethod { } } -// TODO can be made smaller -#[link_section = ".bss"] -static AP_TRAMPOLINE_STACK: BootStack = BootStack { - data: [0; BOOT_STACK_SIZE], -}; - /// Starts application processors using the method specified in the device tree. /// /// TODO: currently does not handle systems where APs are already started before entry. @@ -86,7 +83,7 @@ pub unsafe fn start_ap_cores(dt: &DeviceTree) -> Result<(), Error> { } // Safety: safe, the stack is inside the kernel - let sp = AP_TRAMPOLINE_STACK.data.as_ptr() as usize - KERNEL_VIRT_OFFSET + BOOT_STACK_SIZE; + let sp = AP_TRAMPOLINE_STACK.top_addr() - KERNEL_VIRT_OFFSET; for cpu in enumerate_cpus(dt).filter(|cpu| cpu.id != 0) { debugln!( diff --git a/kernel/src/arch/aarch64/vectors.S b/kernel/src/arch/aarch64/vectors.S index 6f7decac..36642809 100644 --- a/kernel/src/arch/aarch64/vectors.S +++ b/kernel/src/arch/aarch64/vectors.S @@ -8,7 +8,7 @@ .macro EXC_HANDLER el, ht, bits, kind __aa\bits\()_el\el\ht\()_\kind: .if \bits == 32 - // TODO + // TODO 32-bit support b . .endif @@ -49,7 +49,6 @@ __aa\bits\()_el\el\ht\()_\kind: mrs x2, sp_el0 mrs x3, mdscr_el1 - // TODO stp x0, x1, [sp, #16 * 16] stp x2, x3, [sp, #16 * 17] .endm diff --git a/kernel/src/arch/x86_64/apic/ioapic.rs b/kernel/src/arch/x86_64/apic/ioapic.rs index 60157230..5e04476a 100644 --- a/kernel/src/arch/x86_64/apic/ioapic.rs +++ b/kernel/src/arch/x86_64/apic/ioapic.rs @@ -271,11 +271,6 @@ impl IoApic { }); } - // TODO properly map this using DeviceMemory - // let regs = Regs { - // base: unsafe { PhysicalAddress::from_raw(ioapic.address as u64).virtualize_raw() }, - // }; - // let mapping = unsafe { DeviceMemoryMapping::map(base, size) }; let regs = unsafe { DeviceMemoryIo::<'_, Regs>::map( PhysicalAddress::from_u64(ioapic.address as u64), diff --git a/kernel/src/arch/x86_64/boot/mod.rs b/kernel/src/arch/x86_64/boot/mod.rs index d96fa0b6..1f4df929 100644 --- a/kernel/src/arch/x86_64/boot/mod.rs +++ b/kernel/src/arch/x86_64/boot/mod.rs @@ -58,7 +58,6 @@ static YBOOT_DATA: LoadProtocolV1 = LoadProtocolV1 { }; unsafe fn init_dummy_cpu() { - // TODO this is incorrect static UNINIT_CPU_INNER: usize = 0; static UNINIT_CPU_PTR: &usize = &UNINIT_CPU_INNER; diff --git a/kernel/src/arch/x86_64/exception.rs b/kernel/src/arch/x86_64/exception.rs index 370a4963..0e17d762 100644 --- a/kernel/src/arch/x86_64/exception.rs +++ b/kernel/src/arch/x86_64/exception.rs @@ -77,53 +77,6 @@ struct Pointer { offset: usize, } -// impl ExceptionFrame { -// fn dump(&self, level: debug::LogLevel) { -// log_print_raw!(level, " CS:RIP = {:#x}:{:#x}\n", self.cs, self.rip); -// log_print_raw!(level, " SS:RSP = {:#x}:{:#x}\n", self.ss, self.rsp); -// -// log_print_raw!( -// level, -// "RAX = {:#018x}, RCX = {:#018x}\n", -// self.rax, -// self.rcx -// ); -// log_print_raw!( -// level, -// "RDX = {:#018x}, RBX = {:#018x}\n", -// self.rdx, -// self.rbx -// ); -// log_print_raw!( -// level, -// "RSI = {:#018x}, RDI = {:#018x}\n", -// self.rsi, -// self.rdi -// ); -// log_print_raw!(level, "RBP = {:#018x}\n\n", self.rbp); -// -// log_print_raw!(level, " R8 = {:#018x}, R9 = {:#018x}\n", self.r8, self.r9); -// log_print_raw!( -// level, -// "R10 = {:#018x}, R11 = {:#018x}\n", -// self.r10, -// self.r11 -// ); -// log_print_raw!( -// level, -// "R12 = {:#018x}, R13 = {:#018x}\n", -// self.r12, -// self.r13 -// ); -// log_print_raw!( -// level, -// "R14 = {:#018x}, R15 = {:#018x}\n", -// self.r14, -// self.r15 -// ); -// } -// } - const SIZE: usize = 256; impl Entry { diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index ff2ad257..a0898c24 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -194,8 +194,6 @@ impl X86_64 { for l1i in 0..end_l1i { let l2_phys_addr = l2_tables_start.add(l1i * L3::SIZE); - // TODO (minor) the slice is uninitialized, maybe find some way to deal with that - // case nicely // Safety: ok, the mapping is done to the memory obtained from // find_contiguous_region() let mut l2_data = diff --git a/kernel/src/arch/x86_64/smp.rs b/kernel/src/arch/x86_64/smp.rs index c2e97317..02451fd3 100644 --- a/kernel/src/arch/x86_64/smp.rs +++ b/kernel/src/arch/x86_64/smp.rs @@ -112,5 +112,6 @@ pub unsafe fn start_ap_cores(info: &ProcessorInfo) { flush_tlb_entry(0); KERNEL_TABLES.l0.data[0] = 0; - // TODO drop the tables + PageTable::free::(identity_l1); + PageTable::free::(identity_l2); } diff --git a/kernel/src/arch/x86_64/syscall.S b/kernel/src/arch/x86_64/syscall.S index e84f7f17..6b8c5bf9 100644 --- a/kernel/src/arch/x86_64/syscall.S +++ b/kernel/src/arch/x86_64/syscall.S @@ -22,6 +22,9 @@ .set REG_R14, 16 * 8 // .set REG_R15, 17 * 8 // +.set GS_TSS, 0x8 +.set GS_TMP, 0x10 + // 15 general-purpose registers // user ip // user sp @@ -49,7 +52,7 @@ movq %rcx, REG_RCX(%rsp) movq %r11, REG_R11(%rsp) - movq %gs:(16), %rax + movq %gs:(GS_TMP), %rax movq %rcx, REG_USER_IP(%rsp) movq %rax, REG_USER_SP(%rsp) movq %r11, REG_USER_FLAGS(%rsp) @@ -75,10 +78,9 @@ __x86_64_syscall_vector: swapgs // Store user RSP - // TODO: eliminate magic %gs-relative addresses - mov %rsp, %gs:(16) + mov %rsp, %gs:(GS_TMP) // Load the task's RSP0 from TSS - mov %gs:(8), %rsp + mov %gs:(GS_TSS), %rsp mov 4(%rsp), %rsp SYSCALL_SAVE_STATE @@ -133,7 +135,7 @@ __x86_64_syscall_vector: .return_via_sysret: // Regular syscall return movq REG_USER_SP(%rsp), %rcx - movq %rcx, %gs:(16) + movq %rcx, %gs:(GS_TMP) movq REG_USER_IP(%rsp), %rcx movq REG_USER_FLAGS(%rsp), %r11 @@ -142,7 +144,7 @@ __x86_64_syscall_vector: // %rcx and %r11 now contain the expected values // Restore user RSP - mov %gs:(16), %rsp + mov %gs:(GS_TMP), %rsp swapgs sysretq diff --git a/kernel/src/arch/x86_64/syscall.rs b/kernel/src/arch/x86_64/syscall.rs index 01af4665..c8ed2c4f 100644 --- a/kernel/src/arch/x86_64/syscall.rs +++ b/kernel/src/arch/x86_64/syscall.rs @@ -2,8 +2,7 @@ use core::arch::global_asm; -use abi::{process::SignalEntryData, SyscallFunction}; -use kernel_arch::task::TaskFrame; +use abi::SyscallFunction; use kernel_arch_x86_64::{ context::SyscallFrame, registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR}, @@ -11,12 +10,12 @@ use kernel_arch_x86_64::{ use libk::task::{process::Process, thread::Thread}; use tock_registers::interfaces::{ReadWriteable, Writeable}; -use crate::syscall::raw_syscall_handler; +use crate::syscall::{self, raw_syscall_handler}; fn syscall_inner(frame: &mut SyscallFrame) { if frame.rax == usize::from(SyscallFunction::ExitSignal) as u64 { unsafe { - handle_signal_exit(frame); + syscall::handle_signal_exit(frame); return; } } @@ -42,18 +41,6 @@ extern "C" fn __x86_64_syscall_handler(frame: *mut SyscallFrame) { } } -unsafe fn handle_signal_exit(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 diff --git a/kernel/src/device/power/sunxi_rwdog.rs b/kernel/src/device/power/sunxi_rwdog.rs deleted file mode 100644 index a8868427..00000000 --- a/kernel/src/device/power/sunxi_rwdog.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Allwinner (H6) R Watchdog driver - -use abi::error::Error; -use alloc::boxed::Box; -use device_api::{Device, ResetDevice}; -use libk::util::OneTimeInit; -use tock_registers::{ - interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite, -}; - -use crate::{ - arch::{Architecture, PLATFORM}, - device::devtree::{self, DevTreeIndexNodePropGet, DevTreeIndexPropExt}, - device_tree_driver, - mem::device::DeviceMemoryIo, - sync::IrqSafeSpinlock, -}; - -register_bitfields! { - u32, - CTRL [ - KEY OFFSET(1) NUMBITS(12) [ - Value = 0xA57 - ], - RESTART OFFSET(0) NUMBITS(1) [] - ], - CFG [ - CONFIG OFFSET(0) NUMBITS(2) [ - System = 1, - ] - ], - MODE [ - EN OFFSET(0) NUMBITS(1) [], - ] -} - -register_structs! { - #[allow(non_snake_case)] - Regs { - (0x00 => IRQ_EN: ReadWrite), - (0x04 => IRQ_STA: ReadWrite), - (0x08 => _0), - (0x10 => CTRL: ReadWrite), - (0x14 => CFG: ReadWrite), - (0x18 => MODE: ReadWrite), - (0x1C => @END), - } -} - -struct Inner { - regs: DeviceMemoryIo, -} - -struct RWdog { - inner: OneTimeInit>, - base: usize, -} - -impl ResetDevice for RWdog { - unsafe fn reset(&self) -> ! { - // TODO disable IRQs - let inner = self.inner.get().lock(); - - inner.regs.CFG.write(CFG::CONFIG::System); - inner.regs.MODE.write(MODE::EN::SET); - inner.regs.CTRL.write(CTRL::KEY::Value + CTRL::RESTART::SET); - - loop { - core::arch::asm!("wfe"); - } - } -} - -impl Device for RWdog { - fn display_name(&self) -> &'static str { - "Allwinner H6 Watchdog" - } - - unsafe fn init(&'static self) -> Result<(), Error> { - let regs = DeviceMemoryIo::map("r_wdog", self.base)?; - - self.inner.init(IrqSafeSpinlock::new(Inner { regs })); - - PLATFORM.register_reset_device(self)?; - - Ok(()) - } -} - -device_tree_driver! { - compatible: ["allwinner,sun50i-h6-wdt"], - probe(of) => { - let reg = devtree::find_prop(&of.node, "reg")?; - let status: &str = of.node.prop("status").unwrap_or("enabled"); - - if status == "disabled" { - return None; - } - - let (base, _) = reg.cell2_array_item(0, of.address_cells, of.size_cells)?; - let base = base as usize; - - Some(Box::new(RWdog { - inner: OneTimeInit::new(), - base - })) - } -} diff --git a/kernel/src/device/serial/sunxi_uart.rs b/kernel/src/device/serial/sunxi_uart.rs deleted file mode 100644 index 79fac776..00000000 --- a/kernel/src/device/serial/sunxi_uart.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! Allwinner (H6) UART implementation - -use abi::{error::Error, io::DeviceRequest}; -use alloc::boxed::Box; -use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device}; -use libk::util::OneTimeInit; -use tock_registers::{ - interfaces::{ReadWriteable, Readable, Writeable}, - register_bitfields, register_structs, - registers::{ReadOnly, ReadWrite}, -}; -use vfs::CharDevice; - -use crate::{ - arch::{aarch64::IrqNumber, Architecture, PLATFORM}, - debug::{self, DebugSink, LogLevel}, - device::{ - devtree::{self, DevTreeIndexPropExt}, - tty::{CharRing, TtyDevice}, - }, - device_tree_driver, - fs::devfs::{self, CharDeviceType}, - mem::device::DeviceMemoryIo, - sync::IrqSafeSpinlock, -}; - -register_bitfields! { - u32, - USR [ - TFE OFFSET(2) NUMBITS(1) [], - TFNF OFFSET(1) NUMBITS(1) [] - ], - IER [ - ERBFI OFFSET(0) NUMBITS(1) [], - ], - IIR [ - IID OFFSET(0) NUMBITS(4) [ - RecvDataAvailable = 0b0100, - ] - ] -} - -register_structs! { - #[allow(non_snake_case)] - Regs { - (0x00 => DLL: ReadWrite), - (0x04 => IER: ReadWrite), - (0x08 => IIR: ReadWrite), - (0x0C => _0), - (0x7C => USR: ReadOnly), - (0x80 => @END), - } -} - -struct Inner { - regs: DeviceMemoryIo, -} - -struct SunxiUart { - inner: OneTimeInit>, - base: usize, - irq: IrqNumber, - ring: CharRing<16>, -} - -impl DebugSink for SunxiUart { - fn putc(&self, c: u8) -> Result<(), Error> { - self.send(c) - } - - fn supports_control_sequences(&self) -> bool { - true - } -} - -impl CharDevice for SunxiUart { - fn read(&'static self, _blocking: bool, data: &mut [u8]) -> Result { - self.line_read(data) - } - - fn write(&self, _blocking: bool, data: &[u8]) -> Result { - self.line_write(data) - } - - fn device_request(&self, req: &mut DeviceRequest) -> Result<(), Error> { - match req { - &mut DeviceRequest::SetTerminalGroup(id) => { - self.set_signal_group(id as _); - Ok(()) - } - _ => Err(Error::InvalidArgument), - } - } -} - -impl TtyDevice<16> for SunxiUart { - fn ring(&self) -> &CharRing<16> { - &self.ring - } -} - -impl InterruptHandler for SunxiUart { - fn handle_irq(&self) -> bool { - let inner = self.inner.get().lock(); - - if inner.regs.IIR.matches_all(IIR::IID::RecvDataAvailable) { - let byte = inner.regs.DLL.get(); - drop(inner); - - if byte == b'\x1b' as u32 { - panic!("RESET TRIGGERED"); - } - - self.recv_byte(byte as u8); - } - // inner.regs.ICR.write(ICR::ALL::CLEAR); - - // let byte = inner.regs.DR.get(); - // drop(inner); - - // if byte == b'\x1b' as u32 { - // use crate::task::sched::CpuQueue; - - // for (i, queue) in CpuQueue::all().enumerate() { - // log_print_raw!(LogLevel::Fatal, "queue{}:\n", i); - // let lock = unsafe { queue.grab() }; - // for item in lock.iter() { - // log_print_raw!( - // LogLevel::Fatal, - // "* {} {:?} {:?}\n", - // item.id(), - // item.name(), - // item.state() - // ); - // } - // } - // } else { - // self.recv_byte(byte as u8); - // } - - true - } -} - -impl SerialDevice for SunxiUart { - fn send(&self, byte: u8) -> Result<(), Error> { - let inner = self.inner.get().lock(); - if byte == b'\n' { - while inner.regs.USR.matches_all(USR::TFE::CLEAR) { - core::hint::spin_loop(); - } - inner.regs.DLL.set(b'\r' as u32); - } - while inner.regs.USR.matches_all(USR::TFE::CLEAR) { - core::hint::spin_loop(); - } - inner.regs.DLL.set(byte as u32); - Ok(()) - } -} - -impl Device for SunxiUart { - fn display_name(&self) -> &'static str { - "Allwinner UART" - } - - unsafe fn init(&'static self) -> Result<(), Error> { - let regs = DeviceMemoryIo::::map("sunxi-uart", self.base)?; - self.inner.init(IrqSafeSpinlock::new(Inner { regs })); - debug::add_sink(self, LogLevel::Debug); - devfs::add_char_device(self, CharDeviceType::TtySerial)?; - Ok(()) - } - - unsafe fn init_irq(&'static self) -> Result<(), Error> { - let intc = PLATFORM.external_interrupt_controller(); - - intc.register_irq(self.irq, Default::default(), self)?; - intc.enable_irq(self.irq)?; - - let inner = self.inner.get().lock(); - inner.regs.IER.modify(IER::ERBFI::SET); - - Ok(()) - } -} - -device_tree_driver! { - compatible: ["snps,dw-apb-uart"], - probe(of) => { - let reg = devtree::find_prop(&of.node, "reg")?; - let (base, _) = reg.cell2_array_item(0, of.address_cells, of.size_cells)?; - - if base == 0x05000000 { - Some(Box::new(SunxiUart { - inner: OneTimeInit::new(), - ring: CharRing::new(), - irq: IrqNumber::Shared(0), - base: base as usize - })) - } else { - // TODO don't just hardcode and ignore other UARTs - None - } - } -} diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index be554209..a97461de 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -13,6 +13,7 @@ use libk_mm::{ }; use libk_util::OneTimeInit; use memfs::block::{self, BlockAllocator}; +use static_assertions::const_assert_eq; use yggdrasil_abi::{error::Error, io::MountOptions}; // pub mod devfs; @@ -34,10 +35,10 @@ pub static INITRD_DATA: OneTimeInit = OneTimeInit::new(); /// Implementation of [memfs::block::BlockAllocator] for the kernel pub struct FileBlockAllocator; +const_assert_eq!(block::SIZE, 4096); + unsafe impl BlockAllocator for FileBlockAllocator { fn alloc() -> Result, Error> { - // TODO make this a static assertion - assert_eq!(block::SIZE, 4096); let page = phys::alloc_page()?; Ok(unsafe { NonNull::new_unchecked(page.virtualize() as *mut _) }) } diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 3d4b643e..d3dc1939 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -68,7 +68,8 @@ pub fn kinit() -> Result<(), Error> { let mut ioctx = IoContext::new(root); - // TODO maybe better to load this from userspace or along with the kernel + // TODO move this to userspace so it doesn't block the init process, maybe lazy-load on first + // attempt to load a module? load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?; { diff --git a/kernel/src/syscall/arg.rs b/kernel/src/syscall/arg.rs index ad784b8f..50bf3c59 100644 --- a/kernel/src/syscall/arg.rs +++ b/kernel/src/syscall/arg.rs @@ -1,18 +1,22 @@ +//! System call argument validation functions use libk::task::{mem::ForeignPointer, thread::Thread}; use yggdrasil_abi::error::Error; -pub(super) fn ref_const<'a, T: Sized>(addr: usize) -> Result<&'a T, Error> { +/// Validates a &T passed as an address +pub fn ref_const<'a, T: Sized>(addr: usize) -> Result<&'a T, Error> { let proc = Thread::current(); let ptr = addr as *const T; unsafe { ptr.validate_user_ptr(proc.address_space()) } } -pub(super) fn ref_mut<'a, T: Sized>(addr: usize) -> Result<&'a mut T, Error> { +/// Validates a &mut T passed as an address +pub fn ref_mut<'a, T: Sized>(addr: usize) -> Result<&'a mut T, Error> { let proc = Thread::current(); let ptr = addr as *mut T; unsafe { ptr.validate_user_mut(proc.address_space()) } } -pub(super) fn str_ref<'a>(base: usize, len: usize) -> Result<&'a str, Error> { +/// Validates a &str passed as base address and length +pub fn str_ref<'a>(base: usize, len: usize) -> Result<&'a str, Error> { let slice = slice_ref(base, len)?; if slice.contains(&0) { warnln!("User-supplied string contains NUL characters"); @@ -21,12 +25,14 @@ pub(super) fn str_ref<'a>(base: usize, len: usize) -> Result<&'a str, Error> { Ok(core::str::from_utf8(slice).unwrap()) } -pub(super) fn slice_ref<'a, T: Sized>(base: usize, count: usize) -> Result<&'a [T], Error> { +/// Validates a &[T] passed as base address and element count +pub fn slice_ref<'a, T: Sized>(base: usize, count: usize) -> Result<&'a [T], Error> { let proc = Thread::current(); let ptr = base as *const T; unsafe { ptr.validate_user_slice(count, proc.address_space()) } } -pub(super) fn slice_mut<'a, T: Sized>(base: usize, count: usize) -> Result<&'a mut [T], Error> { +/// Validates a &mut [T] passed as base address and element count +pub fn slice_mut<'a, T: Sized>(base: usize, count: usize) -> Result<&'a mut [T], Error> { let proc = Thread::current(); let ptr = base as *mut T; unsafe { ptr.validate_user_slice_mut(count, proc.address_space()) } diff --git a/kernel/src/syscall/imp/sys_process.rs b/kernel/src/syscall/imp/sys_process.rs index d818325a..e34d71a2 100644 --- a/kernel/src/syscall/imp/sys_process.rs +++ b/kernel/src/syscall/imp/sys_process.rs @@ -20,7 +20,7 @@ use libk_mm::{ table::{EntryLevelExt, MapAttributes}, }; -use crate::{arch::L3, proc, syscall::run_with_io}; +use crate::{arch::L3, proc, syscall::run_with_io, util::IteratorExt}; // Memory management pub(crate) fn map_memory( @@ -89,16 +89,20 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result(|entry| { + if let &SpawnOption::AttachDebug(fd) = entry { + let channel = io.files.file(fd)?; + let channel = channel.as_message_channel()?.clone(); - attach_debugger = Some(channel); - } - } + Ok(Some(channel)) + } else { + Ok(None) + } + })?; // Setup a new process from the file let (child_process, child_main) = proc::load_binary( diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 93c3a6df..eec31b4e 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,13 +1,14 @@ //! System function call handlers -use abi::{error::Error, io::RawFd, SyscallFunction}; +use abi::{error::Error, io::RawFd, process::SignalEntryData, SyscallFunction}; +use kernel_arch::task::TaskFrame; use libk::{ task::process::{Process, ProcessIo}, vfs::NodeRef, }; use libk_util::sync::IrqSafeSpinlockGuard; -mod arg; +pub mod arg; mod imp; fn run_with_io) -> T>(proc: &Process, f: F) -> T { @@ -34,6 +35,23 @@ fn run_with_io_at) -> Resu f(at, io) } +/// Handles "return from signal" syscall +pub unsafe fn handle_signal_exit(frame: &mut F) { + let saved_data: &SignalEntryData = match arg::ref_const(frame.argument() as _) { + Ok(r) => r, + Err(err) => { + todo!("Invalid SignalEntryData pointer: {:?}", err) + } + }; + // infoln!( + // "Handling signal exit to ip={:#x}, sp={:#x}", + // saved_data.frame.user_ip, + // saved_data.frame.user_sp + // ); + + frame.restore(&saved_data.frame); +} + mod generated { #![allow(unreachable_code)] diff --git a/kernel/src/util/mod.rs b/kernel/src/util/mod.rs index 11d685cb..3a9a0539 100644 --- a/kernel/src/util/mod.rs +++ b/kernel/src/util/mod.rs @@ -6,6 +6,15 @@ pub trait ResultIterator { fn collect_error(self) -> Option; } +/// Extension trait for [Iterator]s with extra functionality +pub trait IteratorExt { + /// Like find_map(), but with [Result] handling + fn try_find_map Result, E>>( + self, + mapper: F, + ) -> Result, E>; +} + impl>> ResultIterator for I { fn collect_error(self) -> Option { for item in self { @@ -17,6 +26,20 @@ impl>> ResultIterator for I { } } +impl> IteratorExt for I { + fn try_find_map Result, E>>( + self, + mapper: F, + ) -> Result, E> { + for item in self { + if let Some(entry) = mapper(item)? { + return Ok(Some(entry)); + } + } + Ok(None) + } +} + /// Returns the architecture name string pub const fn arch_str() -> &'static str { #[cfg(target_arch = "aarch64")] diff --git a/lib/abi/src/net/types/net_value.rs b/lib/abi/src/net/types/net_value.rs index d1780651..14c7ddf7 100644 --- a/lib/abi/src/net/types/net_value.rs +++ b/lib/abi/src/net/types/net_value.rs @@ -39,7 +39,9 @@ pub trait NetValueImpl: Copy + Eq + bytemuck::Pod + bytemuck::Zeroable { #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] #[repr(transparent)] -pub struct NetValue(T); +pub struct NetValue(T) +where + T: NetValueImpl; /// Helper type for primitive values wrapped in some 1-struct #[cfg(not(feature = "bytemuck"))] diff --git a/lib/qemu/src/lib.rs b/lib/qemu/src/lib.rs index 166d09f3..72c2e69a 100644 --- a/lib/qemu/src/lib.rs +++ b/lib/qemu/src/lib.rs @@ -114,6 +114,12 @@ impl Qemu { self } + pub fn with_smp(&mut self, smp: usize) -> &mut Self { + assert_ne!(smp, 0); + self.smp = Some(smp); + self + } + pub fn disable_display(&mut self) -> &mut Self { self.no_display = true; self diff --git a/xtask/src/qemu.rs b/xtask/src/qemu.rs index 5782a75e..d7e8d819 100644 --- a/xtask/src/qemu.rs +++ b/xtask/src/qemu.rs @@ -39,11 +39,12 @@ struct QemuAArch64MachineConfig { memory: usize, } -#[derive(Debug, Default, serde::Deserialize)] +#[derive(Debug, serde::Deserialize)] #[serde(default)] struct QemuMachineConfig { x86_64: QemuX86_64MachineConfig, aarch64: QemuAArch64MachineConfig, + smp: usize, } #[derive(Debug, Default, serde::Deserialize)] @@ -53,6 +54,16 @@ struct QemuConfig { machine: QemuMachineConfig, } +impl Default for QemuMachineConfig { + fn default() -> Self { + Self { + x86_64: Default::default(), + aarch64: Default::default(), + smp: 4, + } + } +} + impl Default for QemuAArch64MachineConfig { fn default() -> Self { Self { memory: 512 } @@ -106,6 +117,7 @@ fn run_aarch64( } qemu.with_serial(QemuSerialTarget::MonStdio) .with_cpu(aarch64::Cpu::CortexA57) + .with_smp(config.machine.smp) .with_machine(aarch64::Machine::Virt { virtualize: true }) .with_boot_image(aarch64::Image::Kernel { kernel: kernel_bin, @@ -135,6 +147,7 @@ fn run_x86_64( .with_cpu(x86_64::Cpu::Host { enable_kvm: config.machine.x86_64.enable_kvm, }) + .with_smp(config.machine.smp) .with_machine(x86_64::Machine::Q35) .with_boot_slot('a') .with_bios_image(X86_64_UEFI_PATH.into())