use ax_hal::uspace::{ExceptionKind, ReturnReason, UserContext};
use ax_task::TaskInner;
use starry_process::Pid;
use starry_signal::{SignalInfo, Signo};
use starry_vm::{VmMutPtr, VmPtr};
use super::{
AsThread, TimerState, check_signals, raise_signal_fatal, set_timer_state, unblock_next_signal,
};
use crate::syscall::handle_syscall;
pub fn new_user_task(name: &str, mut uctx: UserContext, set_child_tid: usize) -> TaskInner {
TaskInner::new(
move || {
let curr = ax_task::current();
if let Some(tid) = (set_child_tid as *mut Pid).nullable() {
tid.vm_write(curr.id().as_u64() as Pid).ok();
}
info!("Enter user space: ip={:#x}, sp={:#x}", uctx.ip(), uctx.sp());
let thr = curr.as_thread();
while !thr.pending_exit() {
let reason = uctx.run();
set_timer_state(&curr, TimerState::Kernel);
match reason {
ReturnReason::Syscall => handle_syscall(&mut uctx),
ReturnReason::PageFault(addr, flags) => {
if !thr.proc_data.aspace.lock().handle_page_fault(addr, flags) {
info!(
"{:?}: segmentation fault at {:#x} {:?}",
thr.proc_data.proc, addr, flags
);
raise_signal_fatal(SignalInfo::new_kernel(Signo::SIGSEGV))
.expect("Failed to send SIGSEGV");
}
}
ReturnReason::Interrupt => {}
#[allow(unused_labels)]
ReturnReason::Exception(exc_info) => 'exc: {
let signo = match exc_info.kind() {
ExceptionKind::Misaligned => {
#[cfg(target_arch = "loongarch64")]
if unsafe { uctx.emulate_unaligned() }.is_ok() {
break 'exc;
}
Signo::SIGBUS
}
ExceptionKind::Breakpoint => Signo::SIGTRAP,
ExceptionKind::IllegalInstruction => Signo::SIGILL,
_ => Signo::SIGTRAP,
};
raise_signal_fatal(SignalInfo::new_kernel(signo))
.expect("Failed to send SIGTRAP");
}
r => {
warn!("Unexpected return reason: {r:?}");
raise_signal_fatal(SignalInfo::new_kernel(Signo::SIGSEGV))
.expect("Failed to send SIGSEGV");
}
}
if !unblock_next_signal() {
while check_signals(thr, &mut uctx, None) {}
}
set_timer_state(&curr, TimerState::User);
curr.clear_interrupt();
}
},
name.into(),
crate::config::KERNEL_STACK_SIZE,
)
}