kernel: fix some TODOs
This commit is contained in:
parent
a3d7ecd867
commit
b9c1b15bd1
@ -213,6 +213,11 @@ impl<L: EntryLevel> PageTable<L> {
|
|||||||
Ok(table)
|
Ok(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn free<TA: TableAllocator>(this: PhysicalRefMut<Self, KernelTableManagerImpl>) {
|
||||||
|
let physical = this.as_physical_address();
|
||||||
|
TA::free_page_table(physical);
|
||||||
|
}
|
||||||
|
|
||||||
// /// Returns the physical address of this table
|
// /// Returns the physical address of this table
|
||||||
// pub fn physical_address(&self) -> usize {
|
// pub fn physical_address(&self) -> usize {
|
||||||
// unsafe { (self.data.as_ptr() as usize).physicalize() }
|
// unsafe { (self.data.as_ptr() as usize).physicalize() }
|
||||||
|
@ -106,6 +106,7 @@ __aarch64_ap_entry:
|
|||||||
isb
|
isb
|
||||||
|
|
||||||
mov sp, x0
|
mov sp, x0
|
||||||
bl {kernel_ap_lower_entry} - {kernel_virt_offset}
|
MOV_ABS x0, {kernel_ap_lower_entry} - {kernel_virt_offset}
|
||||||
|
blr x0
|
||||||
|
|
||||||
b .
|
b .
|
||||||
|
@ -16,8 +16,12 @@ use libk_mm::{
|
|||||||
};
|
};
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use super::{exception, BootStack, BOOT_STACK_SIZE, PLATFORM};
|
use super::{exception, BootStack, PLATFORM};
|
||||||
use crate::{arch::L3, kernel_main, kernel_secondary_main, mem::KERNEL_VIRT_OFFSET};
|
use crate::{
|
||||||
|
arch::{aarch64::BOOT_STACK_SIZE, L3},
|
||||||
|
kernel_main, kernel_secondary_main,
|
||||||
|
mem::KERNEL_VIRT_OFFSET,
|
||||||
|
};
|
||||||
|
|
||||||
unsafe fn pre_init_mmu() {
|
unsafe fn pre_init_mmu() {
|
||||||
if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran4::Supported) {
|
if !ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran4::Supported) {
|
||||||
@ -51,7 +55,7 @@ unsafe fn enable_mmu() {
|
|||||||
SCTLR_EL1.modify(
|
SCTLR_EL1.modify(
|
||||||
// Enable translation
|
// Enable translation
|
||||||
SCTLR_EL1::M::Enable +
|
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,
|
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();
|
kernel_arch_aarch64::mem::load_fixed_tables();
|
||||||
enable_mmu();
|
enable_mmu();
|
||||||
|
|
||||||
// Safety: SP points to the .bss section, so it's +offset mapped
|
// 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;
|
let sp = BSP_STACK.top_addr() + KERNEL_VIRT_OFFSET;
|
||||||
let elr = absolute_address!(__aarch64_bsp_upper_entry);
|
let elr = absolute_address!(__aarch64_bsp_upper_entry);
|
||||||
|
|
||||||
// TODO pass dtb
|
|
||||||
enter_higher_half(sp, elr, dtb.into_usize());
|
enter_higher_half(sp, elr, dtb.into_usize());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,9 +157,7 @@ extern "C" fn __aarch64_ap_upper_entry() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[link_section = ".bss"]
|
#[link_section = ".bss"]
|
||||||
static BSP_STACK: BootStack = BootStack {
|
static BSP_STACK: BootStack<BOOT_STACK_SIZE> = BootStack::zeroed();
|
||||||
data: [0; BOOT_STACK_SIZE],
|
|
||||||
};
|
|
||||||
|
|
||||||
global_asm!(
|
global_asm!(
|
||||||
include_str!("entry.S"),
|
include_str!("entry.S"),
|
||||||
|
@ -9,16 +9,16 @@ use aarch64_cpu::{
|
|||||||
VBAR_EL1,
|
VBAR_EL1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use abi::{
|
use abi::{process::Signal, SyscallFunction};
|
||||||
process::{Signal, SignalEntryData},
|
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||||
SyscallFunction,
|
|
||||||
};
|
|
||||||
use kernel_arch::{task::TaskFrame, Architecture, ArchitectureImpl};
|
|
||||||
use kernel_arch_aarch64::context::ExceptionFrame;
|
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 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
|
/// Initializes the exception/interrupt vectors. May be called repeatedly (though that makes no
|
||||||
/// sense).
|
/// sense).
|
||||||
@ -32,7 +32,7 @@ pub fn init_exceptions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
|
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, "SYNC exception:\n");
|
||||||
log_print_raw!(LogLevel::Fatal, "FAR: {:#x}\n", FAR_EL1.get());
|
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, "Register dump:\n");
|
||||||
log_print_raw!(LogLevel::Fatal, "{:?}\n", frame);
|
log_print_raw!(LogLevel::Fatal, "{:?}\n", frame);
|
||||||
|
|
||||||
// XXX
|
if let Some(cpu) = cpu {
|
||||||
// if let Some(cpu) = cpu {
|
// let current = cpu.queue().current_process();
|
||||||
// let current = cpu.queue().current_process();
|
let current = cpu.current_thread_id().and_then(Thread::get);
|
||||||
|
|
||||||
// if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
// log_print_raw!(LogLevel::Fatal, "In process {}\n", current.id());
|
log_print_raw!(LogLevel::Fatal, "In thread {}\n", current.id);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
match ec {
|
match ec {
|
||||||
// Data abort from lower level
|
// Data abort from lower level
|
||||||
@ -177,7 +177,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
|
|||||||
let func = frame.r[8];
|
let func = frame.r[8];
|
||||||
if func == usize::from(SyscallFunction::ExitSignal) as u64 {
|
if func == usize::from(SyscallFunction::ExitSignal) as u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
handle_signal_exit(frame);
|
syscall::handle_signal_exit(frame);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -226,16 +226,20 @@ fn irq_common() {
|
|||||||
external_interrupt_controller().handle_pending_irqs();
|
external_interrupt_controller().handle_pending_irqs();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn handle_signal_exit(frame: &mut ExceptionFrame) {
|
// unsafe fn handle_signal_exit(frame: &mut ExceptionFrame) {
|
||||||
// TODO validate the argument
|
// let saved_data: &SignalEntryData = match syscall::arg::ref_const(frame.r[0] as _) {
|
||||||
let saved_data = &*(frame.r[0] as *const SignalEntryData);
|
// Ok(r) => r,
|
||||||
debugln!(
|
// Err(err) => {
|
||||||
"Handling signal exit to pc={:#x}, sp={:#x}",
|
// todo!("Invalid SignalEntryData pointer: {:?}", err)
|
||||||
saved_data.frame.elr_el1,
|
// }
|
||||||
saved_data.frame.sp_el0
|
// };
|
||||||
);
|
// debugln!(
|
||||||
|
// "Handling signal exit to pc={:#x}, sp={:#x}",
|
||||||
frame.restore(&saved_data.frame);
|
// saved_data.frame.elr_el1,
|
||||||
}
|
// saved_data.frame.sp_el0
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// frame.restore(&saved_data.frame);
|
||||||
|
// }
|
||||||
|
|
||||||
global_asm!(include_str!("vectors.S"));
|
global_asm!(include_str!("vectors.S"));
|
||||||
|
@ -99,11 +99,11 @@ impl Gicd {
|
|||||||
assert_eq!(interrupt_id & !0xF, 0);
|
assert_eq!(interrupt_id & !0xF, 0);
|
||||||
let value = match target {
|
let value = match target {
|
||||||
IpiDeliveryTarget::OtherCpus => SGIR::TargetListFilter::AllExceptLocal,
|
IpiDeliveryTarget::OtherCpus => SGIR::TargetListFilter::AllExceptLocal,
|
||||||
IpiDeliveryTarget::Specific(_mask) => {
|
IpiDeliveryTarget::Specific(mask) => {
|
||||||
// TODO: need to handle self-ipi case, releasing the lock somehow
|
assert_eq!(mask & !0xFFFF, 0);
|
||||||
todo!();
|
SGIR::TargetListFilter::SpecifiedOnly + SGIR::CPUTargetList.val(mask as _)
|
||||||
}
|
}
|
||||||
IpiDeliveryTarget::ThisCpu => todo!(),
|
IpiDeliveryTarget::ThisCpu => SGIR::TargetListFilter::LocalOnly,
|
||||||
} + SGIR::INTID.val(interrupt_id as u32);
|
} + SGIR::INTID.val(interrupt_id as u32);
|
||||||
|
|
||||||
self.shared_regs.lock().SGIR.write(value);
|
self.shared_regs.lock().SGIR.write(value);
|
||||||
@ -114,7 +114,6 @@ impl Gicd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_irq(&self, irq: usize, options: IrqOptions) {
|
pub fn configure_irq(&self, irq: usize, options: IrqOptions) {
|
||||||
// TODO configure trigger level
|
|
||||||
// 2 bits per IRQ, 16 entries per register
|
// 2 bits per IRQ, 16 entries per register
|
||||||
let reg = irq / 16;
|
let reg = irq / 16;
|
||||||
let shift = (irq % 16) * 2;
|
let shift = (irq % 16) * 2;
|
||||||
|
@ -163,18 +163,17 @@ impl MessageInterruptController for Gic {
|
|||||||
|
|
||||||
impl LocalInterruptController for Gic {
|
impl LocalInterruptController for Gic {
|
||||||
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> {
|
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> {
|
||||||
// TODO message queue insertion should be moved
|
let local = cpu_index();
|
||||||
match target {
|
let mask = match target {
|
||||||
IpiDeliveryTarget::OtherCpus => {
|
IpiDeliveryTarget::OtherCpus => usize::MAX & !(1 << local),
|
||||||
let local = cpu_index();
|
IpiDeliveryTarget::Specific(mask) => mask,
|
||||||
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!(),
|
|
||||||
IpiDeliveryTarget::ThisCpu => todo!(),
|
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
|
// Issue a memory barrier
|
||||||
|
@ -49,8 +49,8 @@ const BOOT_STACK_SIZE: usize = 4096 * 32;
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(C, align(0x20))]
|
#[repr(C, align(0x20))]
|
||||||
struct BootStack {
|
struct BootStack<const SIZE: usize> {
|
||||||
data: [u8; BOOT_STACK_SIZE],
|
data: [u8; SIZE],
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AArch64 architecture implementation
|
/// AArch64 architecture implementation
|
||||||
@ -64,6 +64,16 @@ pub struct AArch64 {
|
|||||||
initrd: OneTimeInit<PhysicalRef<'static, [u8]>>,
|
initrd: OneTimeInit<PhysicalRef<'static, [u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<const SIZE: usize> BootStack<SIZE> {
|
||||||
|
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 {
|
impl Platform for AArch64 {
|
||||||
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
|
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ use crate::mem::KERNEL_VIRT_OFFSET;
|
|||||||
|
|
||||||
use super::{BootStack, BOOT_STACK_SIZE};
|
use super::{BootStack, BOOT_STACK_SIZE};
|
||||||
|
|
||||||
|
#[link_section = ".bss"]
|
||||||
|
static AP_TRAMPOLINE_STACK: BootStack<BOOT_STACK_SIZE> = BootStack::zeroed();
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum CpuEnableMethod {
|
enum CpuEnableMethod {
|
||||||
Psci,
|
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.
|
/// Starts application processors using the method specified in the device tree.
|
||||||
///
|
///
|
||||||
/// TODO: currently does not handle systems where APs are already started before entry.
|
/// 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
|
// 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) {
|
for cpu in enumerate_cpus(dt).filter(|cpu| cpu.id != 0) {
|
||||||
debugln!(
|
debugln!(
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
.macro EXC_HANDLER el, ht, bits, kind
|
.macro EXC_HANDLER el, ht, bits, kind
|
||||||
__aa\bits\()_el\el\ht\()_\kind:
|
__aa\bits\()_el\el\ht\()_\kind:
|
||||||
.if \bits == 32
|
.if \bits == 32
|
||||||
// TODO
|
// TODO 32-bit support
|
||||||
b .
|
b .
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
@ -49,7 +49,6 @@ __aa\bits\()_el\el\ht\()_\kind:
|
|||||||
mrs x2, sp_el0
|
mrs x2, sp_el0
|
||||||
mrs x3, mdscr_el1
|
mrs x3, mdscr_el1
|
||||||
|
|
||||||
// TODO
|
|
||||||
stp x0, x1, [sp, #16 * 16]
|
stp x0, x1, [sp, #16 * 16]
|
||||||
stp x2, x3, [sp, #16 * 17]
|
stp x2, x3, [sp, #16 * 17]
|
||||||
.endm
|
.endm
|
||||||
|
@ -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 {
|
let regs = unsafe {
|
||||||
DeviceMemoryIo::<'_, Regs>::map(
|
DeviceMemoryIo::<'_, Regs>::map(
|
||||||
PhysicalAddress::from_u64(ioapic.address as u64),
|
PhysicalAddress::from_u64(ioapic.address as u64),
|
||||||
|
@ -58,7 +58,6 @@ static YBOOT_DATA: LoadProtocolV1 = LoadProtocolV1 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
unsafe fn init_dummy_cpu() {
|
unsafe fn init_dummy_cpu() {
|
||||||
// TODO this is incorrect
|
|
||||||
static UNINIT_CPU_INNER: usize = 0;
|
static UNINIT_CPU_INNER: usize = 0;
|
||||||
static UNINIT_CPU_PTR: &usize = &UNINIT_CPU_INNER;
|
static UNINIT_CPU_PTR: &usize = &UNINIT_CPU_INNER;
|
||||||
|
|
||||||
|
@ -77,53 +77,6 @@ struct Pointer {
|
|||||||
offset: usize,
|
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;
|
const SIZE: usize = 256;
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
|
@ -194,8 +194,6 @@ impl X86_64 {
|
|||||||
for l1i in 0..end_l1i {
|
for l1i in 0..end_l1i {
|
||||||
let l2_phys_addr = l2_tables_start.add(l1i * L3::SIZE);
|
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
|
// Safety: ok, the mapping is done to the memory obtained from
|
||||||
// find_contiguous_region()
|
// find_contiguous_region()
|
||||||
let mut l2_data =
|
let mut l2_data =
|
||||||
|
@ -112,5 +112,6 @@ pub unsafe fn start_ap_cores(info: &ProcessorInfo<AcpiAllocator>) {
|
|||||||
flush_tlb_entry(0);
|
flush_tlb_entry(0);
|
||||||
KERNEL_TABLES.l0.data[0] = 0;
|
KERNEL_TABLES.l0.data[0] = 0;
|
||||||
|
|
||||||
// TODO drop the tables
|
PageTable::free::<TableAllocatorImpl>(identity_l1);
|
||||||
|
PageTable::free::<TableAllocatorImpl>(identity_l2);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
.set REG_R14, 16 * 8 //
|
.set REG_R14, 16 * 8 //
|
||||||
.set REG_R15, 17 * 8 //
|
.set REG_R15, 17 * 8 //
|
||||||
|
|
||||||
|
.set GS_TSS, 0x8
|
||||||
|
.set GS_TMP, 0x10
|
||||||
|
|
||||||
// 15 general-purpose registers
|
// 15 general-purpose registers
|
||||||
// user ip
|
// user ip
|
||||||
// user sp
|
// user sp
|
||||||
@ -49,7 +52,7 @@
|
|||||||
movq %rcx, REG_RCX(%rsp)
|
movq %rcx, REG_RCX(%rsp)
|
||||||
movq %r11, REG_R11(%rsp)
|
movq %r11, REG_R11(%rsp)
|
||||||
|
|
||||||
movq %gs:(16), %rax
|
movq %gs:(GS_TMP), %rax
|
||||||
movq %rcx, REG_USER_IP(%rsp)
|
movq %rcx, REG_USER_IP(%rsp)
|
||||||
movq %rax, REG_USER_SP(%rsp)
|
movq %rax, REG_USER_SP(%rsp)
|
||||||
movq %r11, REG_USER_FLAGS(%rsp)
|
movq %r11, REG_USER_FLAGS(%rsp)
|
||||||
@ -75,10 +78,9 @@ __x86_64_syscall_vector:
|
|||||||
swapgs
|
swapgs
|
||||||
|
|
||||||
// Store user RSP
|
// Store user RSP
|
||||||
// TODO: eliminate magic %gs-relative addresses
|
mov %rsp, %gs:(GS_TMP)
|
||||||
mov %rsp, %gs:(16)
|
|
||||||
// Load the task's RSP0 from TSS
|
// Load the task's RSP0 from TSS
|
||||||
mov %gs:(8), %rsp
|
mov %gs:(GS_TSS), %rsp
|
||||||
mov 4(%rsp), %rsp
|
mov 4(%rsp), %rsp
|
||||||
|
|
||||||
SYSCALL_SAVE_STATE
|
SYSCALL_SAVE_STATE
|
||||||
@ -133,7 +135,7 @@ __x86_64_syscall_vector:
|
|||||||
.return_via_sysret:
|
.return_via_sysret:
|
||||||
// Regular syscall return
|
// Regular syscall return
|
||||||
movq REG_USER_SP(%rsp), %rcx
|
movq REG_USER_SP(%rsp), %rcx
|
||||||
movq %rcx, %gs:(16)
|
movq %rcx, %gs:(GS_TMP)
|
||||||
|
|
||||||
movq REG_USER_IP(%rsp), %rcx
|
movq REG_USER_IP(%rsp), %rcx
|
||||||
movq REG_USER_FLAGS(%rsp), %r11
|
movq REG_USER_FLAGS(%rsp), %r11
|
||||||
@ -142,7 +144,7 @@ __x86_64_syscall_vector:
|
|||||||
|
|
||||||
// %rcx and %r11 now contain the expected values
|
// %rcx and %r11 now contain the expected values
|
||||||
// Restore user RSP
|
// Restore user RSP
|
||||||
mov %gs:(16), %rsp
|
mov %gs:(GS_TMP), %rsp
|
||||||
|
|
||||||
swapgs
|
swapgs
|
||||||
sysretq
|
sysretq
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
|
|
||||||
use abi::{process::SignalEntryData, SyscallFunction};
|
use abi::SyscallFunction;
|
||||||
use kernel_arch::task::TaskFrame;
|
|
||||||
use kernel_arch_x86_64::{
|
use kernel_arch_x86_64::{
|
||||||
context::SyscallFrame,
|
context::SyscallFrame,
|
||||||
registers::{MSR_IA32_EFER, MSR_IA32_LSTAR, MSR_IA32_SFMASK, MSR_IA32_STAR},
|
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 libk::task::{process::Process, thread::Thread};
|
||||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
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) {
|
fn syscall_inner(frame: &mut SyscallFrame) {
|
||||||
if frame.rax == usize::from(SyscallFunction::ExitSignal) as u64 {
|
if frame.rax == usize::from(SyscallFunction::ExitSignal) as u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
handle_signal_exit(frame);
|
syscall::handle_signal_exit(frame);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -42,18 +41,6 @@ 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.
|
/// Initializes system call instruction support for the current CPU.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -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<u32>),
|
|
||||||
(0x04 => IRQ_STA: ReadWrite<u32>),
|
|
||||||
(0x08 => _0),
|
|
||||||
(0x10 => CTRL: ReadWrite<u32, CTRL::Register>),
|
|
||||||
(0x14 => CFG: ReadWrite<u32, CFG::Register>),
|
|
||||||
(0x18 => MODE: ReadWrite<u32, MODE::Register>),
|
|
||||||
(0x1C => @END),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Inner {
|
|
||||||
regs: DeviceMemoryIo<Regs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RWdog {
|
|
||||||
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
|
|
||||||
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
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<u32>),
|
|
||||||
(0x04 => IER: ReadWrite<u32, IER::Register>),
|
|
||||||
(0x08 => IIR: ReadWrite<u32, IIR::Register>),
|
|
||||||
(0x0C => _0),
|
|
||||||
(0x7C => USR: ReadOnly<u32, USR::Register>),
|
|
||||||
(0x80 => @END),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Inner {
|
|
||||||
regs: DeviceMemoryIo<Regs>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SunxiUart {
|
|
||||||
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
|
|
||||||
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<usize, Error> {
|
|
||||||
self.line_read(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, _blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
|
||||||
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::<Regs>::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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,6 +13,7 @@ use libk_mm::{
|
|||||||
};
|
};
|
||||||
use libk_util::OneTimeInit;
|
use libk_util::OneTimeInit;
|
||||||
use memfs::block::{self, BlockAllocator};
|
use memfs::block::{self, BlockAllocator};
|
||||||
|
use static_assertions::const_assert_eq;
|
||||||
use yggdrasil_abi::{error::Error, io::MountOptions};
|
use yggdrasil_abi::{error::Error, io::MountOptions};
|
||||||
|
|
||||||
// pub mod devfs;
|
// pub mod devfs;
|
||||||
@ -34,10 +35,10 @@ pub static INITRD_DATA: OneTimeInit<Initrd> = OneTimeInit::new();
|
|||||||
/// Implementation of [memfs::block::BlockAllocator] for the kernel
|
/// Implementation of [memfs::block::BlockAllocator] for the kernel
|
||||||
pub struct FileBlockAllocator;
|
pub struct FileBlockAllocator;
|
||||||
|
|
||||||
|
const_assert_eq!(block::SIZE, 4096);
|
||||||
|
|
||||||
unsafe impl BlockAllocator for FileBlockAllocator {
|
unsafe impl BlockAllocator for FileBlockAllocator {
|
||||||
fn alloc() -> Result<NonNull<u8>, Error> {
|
fn alloc() -> Result<NonNull<u8>, Error> {
|
||||||
// TODO make this a static assertion
|
|
||||||
assert_eq!(block::SIZE, 4096);
|
|
||||||
let page = phys::alloc_page()?;
|
let page = phys::alloc_page()?;
|
||||||
Ok(unsafe { NonNull::new_unchecked(page.virtualize() as *mut _) })
|
Ok(unsafe { NonNull::new_unchecked(page.virtualize() as *mut _) })
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,8 @@ pub fn kinit() -> Result<(), Error> {
|
|||||||
|
|
||||||
let mut ioctx = IoContext::new(root);
|
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")?;
|
load_kernel_symbol_table(&mut ioctx, "/kernel.sym")?;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
|
//! System call argument validation functions
|
||||||
use libk::task::{mem::ForeignPointer, thread::Thread};
|
use libk::task::{mem::ForeignPointer, thread::Thread};
|
||||||
use yggdrasil_abi::error::Error;
|
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 proc = Thread::current();
|
||||||
let ptr = addr as *const T;
|
let ptr = addr as *const T;
|
||||||
unsafe { ptr.validate_user_ptr(proc.address_space()) }
|
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 proc = Thread::current();
|
||||||
let ptr = addr as *mut T;
|
let ptr = addr as *mut T;
|
||||||
unsafe { ptr.validate_user_mut(proc.address_space()) }
|
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)?;
|
let slice = slice_ref(base, len)?;
|
||||||
if slice.contains(&0) {
|
if slice.contains(&0) {
|
||||||
warnln!("User-supplied string contains NUL characters");
|
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())
|
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 proc = Thread::current();
|
||||||
let ptr = base as *const T;
|
let ptr = base as *const T;
|
||||||
unsafe { ptr.validate_user_slice(count, proc.address_space()) }
|
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 proc = Thread::current();
|
||||||
let ptr = base as *mut T;
|
let ptr = base as *mut T;
|
||||||
unsafe { ptr.validate_user_slice_mut(count, proc.address_space()) }
|
unsafe { ptr.validate_user_slice_mut(count, proc.address_space()) }
|
||||||
|
@ -20,7 +20,7 @@ use libk_mm::{
|
|||||||
table::{EntryLevelExt, MapAttributes},
|
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
|
// Memory management
|
||||||
pub(crate) fn map_memory(
|
pub(crate) fn map_memory(
|
||||||
@ -89,16 +89,20 @@ pub(crate) fn spawn_process(options: &SpawnOptions<'_>) -> Result<ProcessId, Err
|
|||||||
let process = thread.process();
|
let process = thread.process();
|
||||||
|
|
||||||
run_with_io(&process, |mut io| {
|
run_with_io(&process, |mut io| {
|
||||||
let mut attach_debugger = None;
|
// let mut attach_debugger = None;
|
||||||
// TODO try_find_map()
|
let attach_debugger = options
|
||||||
for entry in options.optional {
|
.optional
|
||||||
if let &SpawnOption::AttachDebug(fd) = entry {
|
.iter()
|
||||||
let channel = io.files.file(fd)?;
|
.try_find_map::<_, Error, _>(|entry| {
|
||||||
let channel = channel.as_message_channel()?.clone();
|
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
|
// Setup a new process from the file
|
||||||
let (child_process, child_main) = proc::load_binary(
|
let (child_process, child_main) = proc::load_binary(
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
//! System function call handlers
|
//! 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::{
|
use libk::{
|
||||||
task::process::{Process, ProcessIo},
|
task::process::{Process, ProcessIo},
|
||||||
vfs::NodeRef,
|
vfs::NodeRef,
|
||||||
};
|
};
|
||||||
use libk_util::sync::IrqSafeSpinlockGuard;
|
use libk_util::sync::IrqSafeSpinlockGuard;
|
||||||
|
|
||||||
mod arg;
|
pub mod arg;
|
||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(proc: &Process, f: F) -> T {
|
fn run_with_io<T, F: FnOnce(IrqSafeSpinlockGuard<ProcessIo>) -> T>(proc: &Process, f: F) -> T {
|
||||||
@ -34,6 +35,23 @@ fn run_with_io_at<T, F: FnOnce(NodeRef, IrqSafeSpinlockGuard<ProcessIo>) -> Resu
|
|||||||
f(at, io)
|
f(at, io)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles "return from signal" syscall
|
||||||
|
pub unsafe fn handle_signal_exit<F: TaskFrame>(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 {
|
mod generated {
|
||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
|
|
||||||
|
@ -6,6 +6,15 @@ pub trait ResultIterator<T, E> {
|
|||||||
fn collect_error(self) -> Option<E>;
|
fn collect_error(self) -> Option<E>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension trait for [Iterator]s with extra functionality
|
||||||
|
pub trait IteratorExt<T> {
|
||||||
|
/// Like find_map(), but with [Result] handling
|
||||||
|
fn try_find_map<U, E, F: Fn(T) -> Result<Option<U>, E>>(
|
||||||
|
self,
|
||||||
|
mapper: F,
|
||||||
|
) -> Result<Option<U>, E>;
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, E, I: Iterator<Item = Result<T, E>>> ResultIterator<T, E> for I {
|
impl<T, E, I: Iterator<Item = Result<T, E>>> ResultIterator<T, E> for I {
|
||||||
fn collect_error(self) -> Option<E> {
|
fn collect_error(self) -> Option<E> {
|
||||||
for item in self {
|
for item in self {
|
||||||
@ -17,6 +26,20 @@ impl<T, E, I: Iterator<Item = Result<T, E>>> ResultIterator<T, E> for I {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, I: Iterator<Item = T>> IteratorExt<T> for I {
|
||||||
|
fn try_find_map<U, E, F: Fn(T) -> Result<Option<U>, E>>(
|
||||||
|
self,
|
||||||
|
mapper: F,
|
||||||
|
) -> Result<Option<U>, E> {
|
||||||
|
for item in self {
|
||||||
|
if let Some(entry) = mapper(item)? {
|
||||||
|
return Ok(Some(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the architecture name string
|
/// Returns the architecture name string
|
||||||
pub const fn arch_str() -> &'static str {
|
pub const fn arch_str() -> &'static str {
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
@ -39,7 +39,9 @@ pub trait NetValueImpl: Copy + Eq + bytemuck::Pod + bytemuck::Zeroable {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
|
#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct NetValue<T: NetValueImpl>(T);
|
pub struct NetValue<T>(T)
|
||||||
|
where
|
||||||
|
T: NetValueImpl;
|
||||||
|
|
||||||
/// Helper type for primitive values wrapped in some 1-struct
|
/// Helper type for primitive values wrapped in some 1-struct
|
||||||
#[cfg(not(feature = "bytemuck"))]
|
#[cfg(not(feature = "bytemuck"))]
|
||||||
|
@ -114,6 +114,12 @@ impl<A: Architecture> Qemu<A> {
|
|||||||
self
|
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 {
|
pub fn disable_display(&mut self) -> &mut Self {
|
||||||
self.no_display = true;
|
self.no_display = true;
|
||||||
self
|
self
|
||||||
|
@ -39,11 +39,12 @@ struct QemuAArch64MachineConfig {
|
|||||||
memory: usize,
|
memory: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, serde::Deserialize)]
|
#[derive(Debug, serde::Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
struct QemuMachineConfig {
|
struct QemuMachineConfig {
|
||||||
x86_64: QemuX86_64MachineConfig,
|
x86_64: QemuX86_64MachineConfig,
|
||||||
aarch64: QemuAArch64MachineConfig,
|
aarch64: QemuAArch64MachineConfig,
|
||||||
|
smp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, serde::Deserialize)]
|
#[derive(Debug, Default, serde::Deserialize)]
|
||||||
@ -53,6 +54,16 @@ struct QemuConfig {
|
|||||||
machine: QemuMachineConfig,
|
machine: QemuMachineConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for QemuMachineConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
x86_64: Default::default(),
|
||||||
|
aarch64: Default::default(),
|
||||||
|
smp: 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for QemuAArch64MachineConfig {
|
impl Default for QemuAArch64MachineConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { memory: 512 }
|
Self { memory: 512 }
|
||||||
@ -106,6 +117,7 @@ fn run_aarch64(
|
|||||||
}
|
}
|
||||||
qemu.with_serial(QemuSerialTarget::MonStdio)
|
qemu.with_serial(QemuSerialTarget::MonStdio)
|
||||||
.with_cpu(aarch64::Cpu::CortexA57)
|
.with_cpu(aarch64::Cpu::CortexA57)
|
||||||
|
.with_smp(config.machine.smp)
|
||||||
.with_machine(aarch64::Machine::Virt { virtualize: true })
|
.with_machine(aarch64::Machine::Virt { virtualize: true })
|
||||||
.with_boot_image(aarch64::Image::Kernel {
|
.with_boot_image(aarch64::Image::Kernel {
|
||||||
kernel: kernel_bin,
|
kernel: kernel_bin,
|
||||||
@ -135,6 +147,7 @@ fn run_x86_64(
|
|||||||
.with_cpu(x86_64::Cpu::Host {
|
.with_cpu(x86_64::Cpu::Host {
|
||||||
enable_kvm: config.machine.x86_64.enable_kvm,
|
enable_kvm: config.machine.x86_64.enable_kvm,
|
||||||
})
|
})
|
||||||
|
.with_smp(config.machine.smp)
|
||||||
.with_machine(x86_64::Machine::Q35)
|
.with_machine(x86_64::Machine::Q35)
|
||||||
.with_boot_slot('a')
|
.with_boot_slot('a')
|
||||||
.with_bios_image(X86_64_UEFI_PATH.into())
|
.with_bios_image(X86_64_UEFI_PATH.into())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user