From a6b3b953ac3ff11bb1e115574cb362818609bab6 Mon Sep 17 00:00:00 2001 From: AJAX <927068267@qq.com> Date: Fri, 12 Sep 2025 21:18:53 +0800 Subject: [PATCH 01/15] feat (aarch64) UserContext.run can move to user task. when lower exception come, UserContext.run can return a reason. --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/aarch64/asm.rs | 7 +++ src/aarch64/context.rs | 5 ++ src/aarch64/trap.S | 110 +++++++++++++++++++++++++++++++++++- src/aarch64/trap.rs | 87 +++++++++++++++-------------- src/aarch64/uspace.rs | 124 +++++++++++++++++++++++++++++++++++++++++ src/trap.rs | 34 +++++++++++ 8 files changed, 325 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e5dd2c..4723a99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,7 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axbacktrace" version = "0.1.0" -source = "git+https://github.com/Starry-Mix-THU/axbacktrace.git#322f6dab0e7e3f51f7d29731e7eeca6435e5028e" +source = "git+https://github.com/Starry-OS/axbacktrace.git#322f6dab0e7e3f51f7d29731e7eeca6435e5028e" dependencies = [ "cfg-if", "log", diff --git a/Cargo.toml b/Cargo.toml index e3d3201..537ccbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,4 +67,4 @@ targets = [ ] [patch.crates-io] -axbacktrace = { git = "https://github.com/Starry-Mix-THU/axbacktrace.git" } +axbacktrace = { git = "https://github.com/Starry-OS/axbacktrace.git" } diff --git a/src/aarch64/asm.rs b/src/aarch64/asm.rs index f556d3d..327feff 100644 --- a/src/aarch64/asm.rs +++ b/src/aarch64/asm.rs @@ -201,3 +201,10 @@ pub fn enable_fp() { CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing); barrier::isb(barrier::SY); } + +pub fn user_copy(_dst: *mut u8, _src: *const u8, _size: usize) -> usize { + info!( + "Copy user data!" + ); + 0 +} \ No newline at end of file diff --git a/src/aarch64/context.rs b/src/aarch64/context.rs index eeb762a..5fd5dde 100644 --- a/src/aarch64/context.rs +++ b/src/aarch64/context.rs @@ -119,6 +119,11 @@ impl TrapFrame { self.r[0] as _ } + // TODO: + pub const fn sysno(&self) -> usize { + self.r[8] as usize + } + /// Sets the return value register. pub const fn set_retval(&mut self, r0: usize) { self.r[0] = r0 as _; diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index 40761f9..b2c86f9 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -73,6 +73,112 @@ b .Lexception_return .endm +.macro TASK_EXIT, kind, source +.p2align 7 + + # sp => sp_el1 + sub sp, sp, {trapframe_size} + stp x0, x1, [sp] + stp x2, x3, [sp, 2 * 8] + stp x4, x5, [sp, 4 * 8] + stp x6, x7, [sp, 6 * 8] + stp x8, x9, [sp, 8 * 8] + stp x10, x11, [sp, 10 * 8] + stp x12, x13, [sp, 12 * 8] + stp x14, x15, [sp, 14 * 8] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 18 * 8] + stp x20, x21, [sp, 20 * 8] + stp x22, x23, [sp, 22 * 8] + stp x24, x25, [sp, 24 * 8] + stp x26, x27, [sp, 26 * 8] + stp x28, x29, [sp, 28 * 8] + str x30, [sp, 30 * 8] + + mrs x9, sp_el0 + mrs x10, tpidr_el0 + mrs x11, elr_el1 + mrs x12, spsr_el1 + stp x9, x10, [sp, 31 * 8] + stp x11, x12, [sp, 33 * 8] + + # restore kernel tpidr_el0 + mrs x1, tpidrro_el0 + msr tpidr_el0, x1 + + // clear SP_EL0 for kernel use (e.g., to store the current task pointer) + msr sp_el0, xzr + + mov x0, #(1 << (\source * 4 + \kind)) + + add x9, sp, {trapframe_size} + ldr x10, [x9] + mov sp, x10 + + ldp x19, x20, [sp] + ldp x21, x22, [sp, 2 * 8] + ldp x23, x24, [sp, 4 * 8] + ldp x25, x26, [sp, 6 * 8] + ldp x27, x28, [sp, 8 * 8] + ldp x29, x30, [sp, 10 * 8] + add sp, sp, 12 * 8 + + ret + +.endm + + +.global task_in +.p2align 7 +task_in: + sub sp, sp, 12 * 8 + stp x29, x30, [sp,10 * 8] + stp x27, x28, [sp, 8 * 8] + stp x25, x26, [sp, 6 * 8] + stp x23, x24, [sp, 4 * 8] + stp x21, x22, [sp, 2 * 8] + stp x19, x20, [sp, 2 * 0] + mov x9, sp + add x0, x0, {trapframe_size} + str x9, [x0] + + mov sp, x0 // 换上task的el1栈 + + sub sp, sp, {trapframe_size} + mrs x1, tpidr_el0 + msr tpidrro_el0, x1 + + ldp x11, x12, [sp, 33 * 8] + ldp x9, x10, [sp, 31 * 8] + msr sp_el0, x9 + msr tpidr_el0, x10 + msr elr_el1, x11 + msr spsr_el1, x12 + + ldr x30, [sp, 30 * 8] + ldp x28, x29, [sp, 28 * 8] + ldp x26, x27, [sp, 26 * 8] + ldp x24, x25, [sp, 24 * 8] + ldp x22, x23, [sp, 22 * 8] + ldp x20, x21, [sp, 20 * 8] + ldp x18, x19, [sp, 18 * 8] + ldp x16, x17, [sp, 16 * 8] + ldp x14, x15, [sp, 14 * 8] + ldp x12, x13, [sp, 12 * 8] + ldp x10, x11, [sp, 10 * 8] + ldp x8, x9, [sp, 8 * 8] + ldp x6, x7, [sp, 6 * 8] + ldp x4, x5, [sp, 4 * 8] + ldp x2, x3, [sp, 2 * 8] + ldp x0, x1, [sp] + add sp, sp, {trapframe_size} + + eret + +// +// +// + .macro HANDLE_SYNC, source .p2align 7 SAVE_REGS @@ -108,8 +214,8 @@ exception_vector_base: INVALID_EXCP 3 1 // lower EL, aarch64 - HANDLE_SYNC 2 - HANDLE_IRQ 2 + TASK_EXIT 0 2 + TASK_EXIT 1 2 INVALID_EXCP 2 2 INVALID_EXCP 3 2 diff --git a/src/aarch64/trap.rs b/src/aarch64/trap.rs index 8c33a5e..ff711f3 100644 --- a/src/aarch64/trap.rs +++ b/src/aarch64/trap.rs @@ -29,11 +29,11 @@ enum TrapSource { LowerAArch32 = 3, } -impl TrapSource { - fn is_from_user(&self) -> bool { - matches!(self, TrapSource::LowerAArch64 | TrapSource::LowerAArch32) - } -} +// impl TrapSource { +// fn is_from_user(&self) -> bool { +// matches!(self, TrapSource::LowerAArch64 | TrapSource::LowerAArch32) +// } +// } #[unsafe(no_mangle)] fn invalid_exception(tf: &TrapFrame, kind: TrapKind, source: TrapSource) { @@ -44,13 +44,47 @@ fn invalid_exception(tf: &TrapFrame, kind: TrapKind, source: TrapSource) { } #[unsafe(no_mangle)] -fn handle_irq_exception(tf: &mut TrapFrame, source: TrapSource) { - crate::trap::pre_trap_callback(tf, source.is_from_user()); +fn handle_irq_exception(_tf: &mut TrapFrame, _source: TrapSource) { + // crate::trap::pre_trap_callback(tf, source.is_from_user()); handle_trap!(IRQ, 0); - crate::trap::post_trap_callback(tf, source.is_from_user()); + // crate::trap::post_trap_callback(tf, source.is_from_user()); +} + +#[unsafe(no_mangle)] +fn handle_sync_exception(tf: &mut TrapFrame, _source: TrapSource) { + let esr = ESR_EL1.extract(); + let iss = esr.read(ESR_EL1::ISS); + // crate::trap::pre_trap_callback(tf, source.is_from_user()); + match esr.read_as_enum(ESR_EL1::EC) { + #[cfg(feature = "uspace")] + Some(ESR_EL1::EC::Value::SVC64) => { + // Do Not handle syscall here + // tf.r[0] = crate::trap::handle_syscall(tf, tf.r[8] as usize) as u64; + } + Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => handle_instruction_abort(tf, iss, true), + Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => handle_instruction_abort(tf, iss, false), + Some(ESR_EL1::EC::Value::DataAbortLowerEL) => handle_data_abort(tf, iss, true), + Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => handle_data_abort(tf, iss, false), + Some(ESR_EL1::EC::Value::Brk64) => { + debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr); + tf.elr += 4; + } + _ => { + panic!( + "Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})\n{}", + tf.elr, + esr.get(), + esr.read(ESR_EL1::EC), + esr.read(ESR_EL1::ISS), + tf.backtrace() + ); + } + } + // crate::trap::post_trap_callback(tf, source.is_from_user()); } -fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) { + +pub(crate) fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) { let mut access_flags = PageFaultFlags::EXECUTE; if is_user { access_flags |= PageFaultFlags::USER; @@ -59,7 +93,7 @@ fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) { // Only handle Translation fault and Permission fault if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits - || !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) + || !handle_trap!(PAGE_FAULT, vaddr, access_flags) { panic!( "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", @@ -89,7 +123,7 @@ fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) { // Only handle Translation fault and Permission fault if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits - || !handle_trap!(PAGE_FAULT, vaddr, access_flags, is_user) + || !handle_trap!(PAGE_FAULT, vaddr, access_flags) { panic!( "Unhandled {} Data Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", @@ -104,34 +138,3 @@ fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) { } } -#[unsafe(no_mangle)] -fn handle_sync_exception(tf: &mut TrapFrame, source: TrapSource) { - let esr = ESR_EL1.extract(); - let iss = esr.read(ESR_EL1::ISS); - crate::trap::pre_trap_callback(tf, source.is_from_user()); - match esr.read_as_enum(ESR_EL1::EC) { - #[cfg(feature = "uspace")] - Some(ESR_EL1::EC::Value::SVC64) => { - tf.r[0] = crate::trap::handle_syscall(tf, tf.r[8] as usize) as u64; - } - Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => handle_instruction_abort(tf, iss, true), - Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => handle_instruction_abort(tf, iss, false), - Some(ESR_EL1::EC::Value::DataAbortLowerEL) => handle_data_abort(tf, iss, true), - Some(ESR_EL1::EC::Value::DataAbortCurrentEL) => handle_data_abort(tf, iss, false), - Some(ESR_EL1::EC::Value::Brk64) => { - debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr); - tf.elr += 4; - } - _ => { - panic!( - "Unhandled synchronous exception @ {:#x}: ESR={:#x} (EC {:#08b}, ISS {:#x})\n{}", - tf.elr, - esr.get(), - esr.read(ESR_EL1::EC), - esr.read(ESR_EL1::ISS), - tf.backtrace() - ); - } - } - crate::trap::post_trap_callback(tf, source.is_from_user()); -} diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 9f1acc2..547282b 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -107,3 +107,127 @@ impl core::ops::DerefMut for UspaceContext { &mut self.0 } } + + + +use crate::trap::{ExceptionKind, ReturnReason}; +use core::ops::{Deref, DerefMut}; + +#[derive(Debug, Clone, Copy)] +pub struct ExceptionInfo { + // pub e: E, + pub stval: usize, +} + +impl ExceptionInfo { + pub fn kind(&self) -> ExceptionKind { + // match self.e { + // E::Breakpoint => ExceptionKind::Breakpoint, + // E::IllegalInstruction => ExceptionKind::IllegalInstruction, + // E::InstructionMisaligned | E::LoadMisaligned | E::StoreMisaligned => { + // ExceptionKind::Misaligned + // } + // _ => ExceptionKind::Other, + // } + + ExceptionKind::Other + } +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct UserContext { + tf: TrapFrame, + sp_el1: u64, +} + +impl Deref for UserContext { + type Target = TrapFrame; + + fn deref(&self) -> &Self::Target { + &self.tf + } +} + +impl DerefMut for UserContext { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.tf + } +} + +impl From for UserContext { + fn from(tf: TrapFrame) -> Self { + Self { + tf, + sp_el1: 0, // 默认初始化 + } + } +} + + +use crate::aarch64::trap::handle_instruction_abort; + +impl UserContext { + pub fn run(&mut self) -> ReturnReason { + extern "C" { + pub fn task_in(base: usize) -> u16; + } + + // test => 0x82000004 + // let addr: *mut u64 = 0xffff_0000_45a0_0000 as *mut u64; + // unsafe { + // core::ptr::write_volatile(addr, 0); + // } + + let base_addr: usize = self as *mut Self as usize; + let ret: u16 = unsafe { task_in(base_addr) }; + + // 读取 ESR + let esr = unsafe { + let esr_val: u32; + core::arch::asm!("mrs {0:x}, esr_el1", out(reg) esr_val); + esr_val + }; + let ec = (esr >> 26) & 0x3f; + let iss = esr & 0x01ff_ffff; // 低 25 位 + + info!("reason: {:#x}, esr: {:#x} ", ret, esr, ec, iss); + + match ec { + 0x15 => { // SVC call + ReturnReason::Syscall + }, + 0x20 => { // Translation fault, level 1. + let ttbr0_el1: u64; + unsafe { + core::arch::asm!( + "mrs {0}, ttbr0_el1", + out(reg) ttbr0_el1 + ); + } + + handle_instruction_abort(self, iss as u64, true); + + info!("TTBR0_EL1 = {:#x}", ttbr0_el1); + info!("{:#?}", self); + panic!("Translation fault, level 1."); + } + _ => ReturnReason::Unknown + } + + } + + pub fn new(entry: usize, ustack_top: VirtAddr, _arg0: usize) -> Self { + info!("new ctx: entry={:#x}, ustack_top={:#x}", entry, ustack_top.as_usize()); + Self { + tf: TrapFrame { + r: [0u64; 31], + usp: ustack_top.as_usize() as u64, // 假设 VirtAddr 有 as_u64 方法 + tpidr: 0, + elr: entry as u64, // 用户入口地址 + spsr: 0 | (0b0000<<4), // 可根据 EL 设置初值 // 0001 0000 1100 0111 0000 + }, + sp_el1: 0, // EL1 栈指针 + } + } +} \ No newline at end of file diff --git a/src/trap.rs b/src/trap.rs index 001b88f..5fb5d09 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -33,6 +33,26 @@ macro_rules! handle_trap { }} } + +#[derive(Debug, Clone, Copy)] +pub enum ExceptionSource { + CurrentSpEl0 = 0, + CurrentSpElx = 1, + LowerAarch64 = 2, + LowerAarch32 = 3, +} + +pub const fn excp_mask(kind: u8, source: ExceptionSource) -> u16 { + 1 << ((source as u8) * 4 + kind) +} + +// 用例 +pub const TASK_EXIT_0_1: u16 = excp_mask(0, ExceptionSource::CurrentSpElx); +pub const TASK_EXIT_1_1: u16 = excp_mask(1, ExceptionSource::CurrentSpElx); +pub const TASK_EXIT_0_2: u16 = excp_mask(0, ExceptionSource::LowerAarch64); +pub const TASK_EXIT_1_2: u16 = excp_mask(1, ExceptionSource::LowerAarch64); +// 0x10, 0x20, 0x100, 0x200 + #[cfg(feature = "uspace")] #[derive(Debug, Clone, Copy)] pub enum ReturnReason { @@ -43,6 +63,20 @@ pub enum ReturnReason { Exception(crate::uspace::ExceptionInfo), } +impl ReturnReason { + /// 从 task_in() 返回的 bitmask 解码 + pub fn from_mask(mask: u16) -> Self { + match mask { + TASK_EXIT_0_1 => ReturnReason::Syscall, // TASK_EXIT 0 1 + TASK_EXIT_1_1 => ReturnReason::Interrupt, // TASK_EXIT 1 1 + TASK_EXIT_0_2 => ReturnReason::Syscall, + TASK_EXIT_1_2 => ReturnReason::Interrupt, + _ => ReturnReason::Unknown, + } + } + +} + #[cfg(feature = "uspace")] pub enum ExceptionKind { Other, From d00ddf9a2a2790f21603ae16819fa7e84b5d75b8 Mon Sep 17 00:00:00 2001 From: AJAX <927068267@qq.com> Date: Sat, 13 Sep 2025 23:54:32 +0800 Subject: [PATCH 02/15] handle lower exception in proper position. --- src/aarch64/trap.rs | 1 + src/aarch64/uspace.rs | 115 +++++++++++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/aarch64/trap.rs b/src/aarch64/trap.rs index ff711f3..a67c724 100644 --- a/src/aarch64/trap.rs +++ b/src/aarch64/trap.rs @@ -54,6 +54,7 @@ fn handle_irq_exception(_tf: &mut TrapFrame, _source: TrapSource) { fn handle_sync_exception(tf: &mut TrapFrame, _source: TrapSource) { let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); + warn!("handle trap in current el!"); // crate::trap::pre_trap_callback(tf, source.is_from_user()); match esr.read_as_enum(ESR_EL1::EC) { #[cfg(feature = "uspace")] diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 547282b..6f860e3 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -165,7 +165,68 @@ impl From for UserContext { } -use crate::aarch64::trap::handle_instruction_abort; +use page_table_entry::MappingFlags; +use aarch64_cpu::registers::FAR_EL1; +use aarch64_cpu::registers::ESR_EL1; +use aarch64_cpu::registers::Readable; + +fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReason { + let mut access_flags = MappingFlags::EXECUTE; + if is_user { + access_flags |= MappingFlags::USER; + } + let vaddr = va!(FAR_EL1.get() as usize); + + // Only handle Translation fault and Permission fault + if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits + { + panic!( + "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", + if is_user { "EL0" } else { "EL1" }, + tf.elr, + vaddr, + ESR_EL1.get(), + access_flags, + tf, + tf.backtrace() + ); + } else { + ReturnReason::PageFault(vaddr, access_flags) + } +} + + +fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReason { + let wnr = (iss & (1 << 6)) != 0; // WnR: Write not Read + let cm = (iss & (1 << 8)) != 0; // CM: Cache maintenance + let mut access_flags = if wnr & !cm { + MappingFlags::WRITE + } else { + MappingFlags::READ + }; + if is_user { + access_flags |= MappingFlags::USER; + } + let vaddr = va!(FAR_EL1.get() as usize); + + // Only handle Translation fault and Permission fault + if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits + { + panic!( + "Unhandled {} Data Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", + if is_user { "EL0" } else { "EL1" }, + tf.elr, + vaddr, + ESR_EL1.get(), + access_flags, + tf, + tf.backtrace() + ); + } else { + ReturnReason::PageFault(vaddr, access_flags) + } +} + impl UserContext { pub fn run(&mut self) -> ReturnReason { @@ -173,44 +234,28 @@ impl UserContext { pub fn task_in(base: usize) -> u16; } - // test => 0x82000004 - // let addr: *mut u64 = 0xffff_0000_45a0_0000 as *mut u64; - // unsafe { - // core::ptr::write_volatile(addr, 0); - // } - let base_addr: usize = self as *mut Self as usize; - let ret: u16 = unsafe { task_in(base_addr) }; + let el1_sp = self.sp_el1; + + warn!("task in {:#x}, elr: {:#x}, el1 stack {:#x}", + base_addr, self.tf.elr, el1_sp); - // 读取 ESR - let esr = unsafe { - let esr_val: u32; - core::arch::asm!("mrs {0:x}, esr_el1", out(reg) esr_val); - esr_val - }; - let ec = (esr >> 26) & 0x3f; - let iss = esr & 0x01ff_ffff; // 低 25 位 - - info!("reason: {:#x}, esr: {:#x} ", ret, esr, ec, iss); - - match ec { - 0x15 => { // SVC call + let _: u16 = unsafe { task_in(base_addr) }; + let esr = ESR_EL1.extract(); + let iss = esr.read(ESR_EL1::ISS); + + match esr.read_as_enum(ESR_EL1::EC) { + Some(ESR_EL1::EC::Value::SVC64) => { + info!("task return because syscall ..."); ReturnReason::Syscall }, - 0x20 => { // Translation fault, level 1. - let ttbr0_el1: u64; - unsafe { - core::arch::asm!( - "mrs {0}, ttbr0_el1", - out(reg) ttbr0_el1 - ); - } - - handle_instruction_abort(self, iss as u64, true); - - info!("TTBR0_EL1 = {:#x}", ttbr0_el1); - info!("{:#?}", self); - panic!("Translation fault, level 1."); + Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { + info!("task return because InstrAbortLowerEL ..."); + handle_instruction_abort_lower(&self.tf, iss, true) + } + Some(ESR_EL1::EC::Value::DataAbortLowerEL) => { + info!("task return because DataAbortLowerEL ..."); + handle_data_abort_lower(&self.tf, iss, true) } _ => ReturnReason::Unknown } From d4c39e8fb84705ad62091dd3b00bd8590f29e0e1 Mon Sep 17 00:00:00 2001 From: AJAX <927068267@qq.com> Date: Sun, 14 Sep 2025 16:03:32 +0800 Subject: [PATCH 03/15] add some debug fn --- src/aarch64/trap.S | 59 +++++++++++++++++++++++++------------------ src/aarch64/uspace.rs | 39 ++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index b2c86f9..3327790 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -122,11 +122,13 @@ ldp x27, x28, [sp, 8 * 8] ldp x29, x30, [sp, 10 * 8] add sp, sp, 12 * 8 - + cbz x30, .Ldeadloop ret .endm +.Ldeadloop: + b .Ldeadloop .global task_in .p2align 7 @@ -201,29 +203,38 @@ task_in: .p2align 11 .global exception_vector_base exception_vector_base: - // current EL, with SP_EL0 - INVALID_EXCP 0 0 - INVALID_EXCP 1 0 - INVALID_EXCP 2 0 - INVALID_EXCP 3 0 - - // current EL, with SP_ELx - HANDLE_SYNC 1 - HANDLE_IRQ 1 - INVALID_EXCP 2 1 - INVALID_EXCP 3 1 - - // lower EL, aarch64 - TASK_EXIT 0 2 - TASK_EXIT 1 2 - INVALID_EXCP 2 2 - INVALID_EXCP 3 2 - - // lower EL, aarch32 - INVALID_EXCP 0 3 - INVALID_EXCP 1 3 - INVALID_EXCP 2 3 - INVALID_EXCP 3 3 +curr_el_sp0_sync: + INVALID_EXCP 0 0 +curr_el_sp0_irq: + INVALID_EXCP 1 0 +curr_el_sp0_fiq: + INVALID_EXCP 2 0 +curr_el_sp0_serror: + INVALID_EXCP 3 0 +curr_el_spx_sync: + HANDLE_SYNC 1 +curr_el_spx_irq: + HANDLE_IRQ 1 +curr_el_spx_fiq: + INVALID_EXCP 2 1 +curr_el_spx_serror: + INVALID_EXCP 3 1 +lower_el_aarch64_sync: + TASK_EXIT 0 2 +lower_el_aarch64_irq: + TASK_EXIT 1 2 +lower_el_aarch64_fiq: + INVALID_EXCP 2 2 +lower_el_aarch64_serror: + INVALID_EXCP 3 2 +lower_el_aarch32_sync: + INVALID_EXCP 0 3 +lower_el_aarch32_irq: + INVALID_EXCP 1 3 +lower_el_aarch32_fiq: + INVALID_EXCP 2 3 +lower_el_aarch32_serror: + INVALID_EXCP 3 3 .Lexception_return: RESTORE_REGS diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 6f860e3..9b3f0b2 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -228,6 +228,45 @@ fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReas } +/// Compare two memory regions as u64 words, dump both if any difference found. +/// +/// # Safety +/// Caller must ensure both addr1 and addr2 are valid for `num_words * 8` bytes. +pub unsafe fn compare_and_dump_u64(addr1: usize, addr2: usize, num_words: usize) -> bool { + let ptr1 = addr1 as *const u64; + let ptr2 = addr2 as *const u64; + + let mut equal = true; + + for i in 0..num_words { + let val1 = *ptr1.add(i); + let val2 = *ptr2.add(i); + if val1 != val2 { + equal = false; + break; + } + } + + if !equal { + warn!("Memory regions differ, dumping contents:"); + + warn!("Region 1 at {:#x}:", addr1); + for i in 0..num_words { + let val = *ptr1.add(i); + warn!(" [{:02}] = {:#018x}", i, val); + } + + warn!("Region 2 at {:#x}:", addr2); + for i in 0..num_words { + let val = *ptr2.add(i); + warn!(" [{:02}] = {:#018x}", i, val); + } + } + + equal +} + + impl UserContext { pub fn run(&mut self) -> ReturnReason { extern "C" { From 06e04bd10b26933bbfdedd03d93a9a445a383eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 17 Sep 2025 16:50:12 +0800 Subject: [PATCH 04/15] user_entry --- src/aarch64/trap.S | 51 ------------------ src/aarch64/uspace.rs | 119 ++++++++++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 83 deletions(-) diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index 3327790..caf37a0 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -130,57 +130,6 @@ .Ldeadloop: b .Ldeadloop -.global task_in -.p2align 7 -task_in: - sub sp, sp, 12 * 8 - stp x29, x30, [sp,10 * 8] - stp x27, x28, [sp, 8 * 8] - stp x25, x26, [sp, 6 * 8] - stp x23, x24, [sp, 4 * 8] - stp x21, x22, [sp, 2 * 8] - stp x19, x20, [sp, 2 * 0] - mov x9, sp - add x0, x0, {trapframe_size} - str x9, [x0] - - mov sp, x0 // 换上task的el1栈 - - sub sp, sp, {trapframe_size} - mrs x1, tpidr_el0 - msr tpidrro_el0, x1 - - ldp x11, x12, [sp, 33 * 8] - ldp x9, x10, [sp, 31 * 8] - msr sp_el0, x9 - msr tpidr_el0, x10 - msr elr_el1, x11 - msr spsr_el1, x12 - - ldr x30, [sp, 30 * 8] - ldp x28, x29, [sp, 28 * 8] - ldp x26, x27, [sp, 26 * 8] - ldp x24, x25, [sp, 24 * 8] - ldp x22, x23, [sp, 22 * 8] - ldp x20, x21, [sp, 20 * 8] - ldp x18, x19, [sp, 18 * 8] - ldp x16, x17, [sp, 16 * 8] - ldp x14, x15, [sp, 14 * 8] - ldp x12, x13, [sp, 12 * 8] - ldp x10, x11, [sp, 10 * 8] - ldp x8, x9, [sp, 8 * 8] - ldp x6, x7, [sp, 6 * 8] - ldp x4, x5, [sp, 4 * 8] - ldp x2, x3, [sp, 2 * 8] - ldp x0, x1, [sp] - add sp, sp, {trapframe_size} - - eret - -// -// -// - .macro HANDLE_SYNC, source .p2align 7 SAVE_REGS diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 9b3f0b2..06020b3 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -2,7 +2,7 @@ use memory_addr::VirtAddr; -use crate::TrapFrame; +use crate::{TrapFrame, aarch64::trap}; /// Context to enter user space. pub struct UspaceContext(TrapFrame); @@ -108,10 +108,14 @@ impl core::ops::DerefMut for UspaceContext { } } - +use core::{ + arch::naked_asm, + mem::offset_of, + ops::{Deref, DerefMut}, + ptr::addr_of, +}; use crate::trap::{ExceptionKind, ReturnReason}; -use core::ops::{Deref, DerefMut}; #[derive(Debug, Clone, Copy)] pub struct ExceptionInfo { @@ -159,18 +163,15 @@ impl From for UserContext { fn from(tf: TrapFrame) -> Self { Self { tf, - sp_el1: 0, // 默认初始化 + sp_el1: 0, // 默认初始化 } } } - +use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; use page_table_entry::MappingFlags; -use aarch64_cpu::registers::FAR_EL1; -use aarch64_cpu::registers::ESR_EL1; -use aarch64_cpu::registers::Readable; -fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReason { +fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { let mut access_flags = MappingFlags::EXECUTE; if is_user { access_flags |= MappingFlags::USER; @@ -178,10 +179,12 @@ fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> Ret let vaddr = va!(FAR_EL1.get() as usize); // Only handle Translation fault and Permission fault - if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits + if !matches!(iss & 0b111100, 0b0100 | 0b1100) + // IFSC or DFSC bits { panic!( - "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", + "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} \ + ({:?}):\n{:#x?}\n{}", if is_user { "EL0" } else { "EL1" }, tf.elr, vaddr, @@ -195,8 +198,7 @@ fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> Ret } } - -fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReason { +fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { let wnr = (iss & (1 << 6)) != 0; // WnR: Write not Read let cm = (iss & (1 << 8)) != 0; // CM: Cache maintenance let mut access_flags = if wnr & !cm { @@ -210,7 +212,8 @@ fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReas let vaddr = va!(FAR_EL1.get() as usize); // Only handle Translation fault and Permission fault - if !matches!(iss & 0b111100, 0b0100 | 0b1100) // IFSC or DFSC bits + if !matches!(iss & 0b111100, 0b0100 | 0b1100) + // IFSC or DFSC bits { panic!( "Unhandled {} Data Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", @@ -227,7 +230,6 @@ fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool)-> ReturnReas } } - /// Compare two memory regions as u64 words, dump both if any difference found. /// /// # Safety @@ -266,20 +268,16 @@ pub unsafe fn compare_and_dump_u64(addr1: usize, addr2: usize, num_words: usize) equal } - impl UserContext { pub fn run(&mut self) -> ReturnReason { - extern "C" { - pub fn task_in(base: usize) -> u16; + debug!( + "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x}", + self.tf.elr, self.sp_el1, self.tf.usp + ); + unsafe { + enter_user(self); } - let base_addr: usize = self as *mut Self as usize; - let el1_sp = self.sp_el1; - - warn!("task in {:#x}, elr: {:#x}, el1 stack {:#x}", - base_addr, self.tf.elr, el1_sp); - - let _: u16 = unsafe { task_in(base_addr) }; let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); @@ -287,7 +285,7 @@ impl UserContext { Some(ESR_EL1::EC::Value::SVC64) => { info!("task return because syscall ..."); ReturnReason::Syscall - }, + } Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { info!("task return because InstrAbortLowerEL ..."); handle_instruction_abort_lower(&self.tf, iss, true) @@ -296,22 +294,79 @@ impl UserContext { info!("task return because DataAbortLowerEL ..."); handle_data_abort_lower(&self.tf, iss, true) } - _ => ReturnReason::Unknown + _ => ReturnReason::Unknown, } - } pub fn new(entry: usize, ustack_top: VirtAddr, _arg0: usize) -> Self { - info!("new ctx: entry={:#x}, ustack_top={:#x}", entry, ustack_top.as_usize()); + info!( + "new ctx: entry={:#x}, ustack_top={:#x}", + entry, + ustack_top.as_usize() + ); Self { tf: TrapFrame { r: [0u64; 31], usp: ustack_top.as_usize() as u64, // 假设 VirtAddr 有 as_u64 方法 tpidr: 0, elr: entry as u64, // 用户入口地址 - spsr: 0 | (0b0000<<4), // 可根据 EL 设置初值 // 0001 0000 1100 0111 0000 + spsr: 0 | (0b0000 << 4), // 可根据 EL 设置初值 // 0001 0000 1100 0111 0000 }, - sp_el1: 0, // EL1 栈指针 + sp_el1: 0, // EL1 栈指针 } } -} \ No newline at end of file +} + +#[unsafe(naked)] +unsafe extern "C" fn enter_user(_ctx: &mut UserContext) { + naked_asm!( + " + sub sp, sp, 12 * 8 + stp x29, x30, [sp,10 * 8] + stp x27, x28, [sp, 8 * 8] + stp x25, x26, [sp, 6 * 8] + stp x23, x24, [sp, 4 * 8] + stp x21, x22, [sp, 2 * 8] + stp x19, x20, [sp, 2 * 0] + + mov x8, sp + msr sp_el1, x8 + + str x8, [x0, {sp_el1}] + + // -- restore user context -- + + mrs x8, tpidr_el0 + msr tpidrro_el0, x8 + + ldp x8, x9, [x0, {elr_el1}] + msr elr_el1, x8 + msr spsr_el1, x9 + + ldp x8, x9, [x0, {sp_el0}] + msr sp_el0, x8 + msr tpidr_el0, x9 + + ldr x30, [x0, 30 * 8] + ldp x28, x29, [x0, 28 * 8] + ldp x26, x27, [x0, 26 * 8] + ldp x24, x25, [x0, 24 * 8] + ldp x22, x23, [x0, 22 * 8] + ldp x20, x21, [x0, 20 * 8] + ldp x18, x19, [x0, 18 * 8] + ldp x16, x17, [x0, 16 * 8] + ldp x14, x15, [x0, 14 * 8] + ldp x12, x13, [x0, 12 * 8] + ldp x10, x11, [x0, 10 * 8] + ldp x8, x9, [x0, 8 * 8] + ldp x6, x7, [x0, 6 * 8] + ldp x4, x5, [x0, 4 * 8] + ldp x2, x3, [x0, 2 * 8] + ldp x0, x1, [x0] + eret + ", + sp_el1 = const offset_of!(UserContext, sp_el1), + elr_el1 = const offset_of!(TrapFrame, elr), + sp_el0 = const offset_of!(TrapFrame, usp), + ) +} From fe440f9f7d0d044a301e3a1c892eaa7af321070d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Wed, 17 Sep 2025 17:23:43 +0800 Subject: [PATCH 05/15] add task exit --- src/aarch64/trap.S | 41 ----------------------------------------- src/aarch64/uspace.rs | 11 +++++++---- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index caf37a0..4f75846 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -76,53 +76,12 @@ .macro TASK_EXIT, kind, source .p2align 7 - # sp => sp_el1 - sub sp, sp, {trapframe_size} - stp x0, x1, [sp] - stp x2, x3, [sp, 2 * 8] - stp x4, x5, [sp, 4 * 8] - stp x6, x7, [sp, 6 * 8] - stp x8, x9, [sp, 8 * 8] - stp x10, x11, [sp, 10 * 8] - stp x12, x13, [sp, 12 * 8] - stp x14, x15, [sp, 14 * 8] - stp x16, x17, [sp, 16 * 8] - stp x18, x19, [sp, 18 * 8] - stp x20, x21, [sp, 20 * 8] - stp x22, x23, [sp, 22 * 8] - stp x24, x25, [sp, 24 * 8] - stp x26, x27, [sp, 26 * 8] - stp x28, x29, [sp, 28 * 8] - str x30, [sp, 30 * 8] - - mrs x9, sp_el0 - mrs x10, tpidr_el0 - mrs x11, elr_el1 - mrs x12, spsr_el1 - stp x9, x10, [sp, 31 * 8] - stp x11, x12, [sp, 33 * 8] - - # restore kernel tpidr_el0 - mrs x1, tpidrro_el0 - msr tpidr_el0, x1 - - // clear SP_EL0 for kernel use (e.g., to store the current task pointer) - msr sp_el0, xzr - - mov x0, #(1 << (\source * 4 + \kind)) - - add x9, sp, {trapframe_size} - ldr x10, [x9] - mov sp, x10 - ldp x19, x20, [sp] ldp x21, x22, [sp, 2 * 8] ldp x23, x24, [sp, 4 * 8] ldp x25, x26, [sp, 6 * 8] ldp x27, x28, [sp, 8 * 8] ldp x29, x30, [sp, 10 * 8] - add sp, sp, 12 * 8 - cbz x30, .Ldeadloop ret .endm diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 06020b3..b48dfe7 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -168,7 +168,7 @@ impl From for UserContext { } } -use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; +use aarch64_cpu::registers::{CurrentEL, ESR_EL1, FAR_EL1, Readable}; use page_table_entry::MappingFlags; fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { @@ -271,13 +271,16 @@ pub unsafe fn compare_and_dump_u64(addr1: usize, addr2: usize, num_words: usize) impl UserContext { pub fn run(&mut self) -> ReturnReason { debug!( - "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x}", - self.tf.elr, self.sp_el1, self.tf.usp + "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x}, el{}", + self.tf.elr, + self.sp_el1, + self.tf.usp, + CurrentEL.read(CurrentEL::EL) ); unsafe { enter_user(self); } - + debug!("Returned from user space"); let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); From d7a08598f95de0299c8563ba1f565bf2e8a379d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 10:06:36 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E9=80=80=E5=87=BA=E5=AE=8F=EF=BC=8C=E4=BD=BF=E7=94=A8SAVE=5FRE?= =?UTF-8?q?GS=E5=AE=8F=E4=BF=9D=E5=AD=98=E5=AF=84=E5=AD=98=E5=99=A8?= =?UTF-8?q?=E7=8A=B6=E6=80=81=EF=BC=8C=E5=B9=B6=E6=B7=BB=E5=8A=A0=5Fuser?= =?UTF-8?q?=5Ftrap=5Fentry=E5=87=BD=E6=95=B0=E4=BB=A5=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=99=B7=E9=98=B1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aarch64/trap.S | 12 +--- src/aarch64/uspace.rs | 139 +++++++++++++++--------------------------- 2 files changed, 53 insertions(+), 98 deletions(-) diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index 4f75846..72870aa 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -36,7 +36,7 @@ # backup kernel tpidr_el0 mrs x1, tpidr_el0 msr tpidrro_el0, x1 - + ldp x11, x12, [sp, 33 * 8] ldp x9, x10, [sp, 31 * 8] msr sp_el0, x9 @@ -75,14 +75,8 @@ .macro TASK_EXIT, kind, source .p2align 7 - - ldp x19, x20, [sp] - ldp x21, x22, [sp, 2 * 8] - ldp x23, x24, [sp, 4 * 8] - ldp x25, x26, [sp, 6 * 8] - ldp x27, x28, [sp, 8 * 8] - ldp x29, x30, [sp, 10 * 8] - ret + SAVE_REGS + b _user_trap_entry .endm diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index b48dfe7..c5f4fc8 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -2,7 +2,7 @@ use memory_addr::VirtAddr; -use crate::{TrapFrame, aarch64::trap}; +use crate::TrapFrame; /// Context to enter user space. pub struct UspaceContext(TrapFrame); @@ -37,61 +37,6 @@ impl UspaceContext { pub const fn from(trap_frame: &TrapFrame) -> Self { Self(*trap_frame) } - - /// Enters user space. - /// - /// It restores the user registers and jumps to the user entry point - /// (saved in `elr`). - /// When an exception or syscall occurs, the kernel stack pointer is - /// switched to `kstack_top`. - /// - /// # Safety - /// - /// This function is unsafe because it changes processor mode and the stack. - pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! { - crate::asm::disable_irqs(); - // We do not handle traps that occur at the current exception level, - // so the kstack ptr(`sp_el1`) will not change during running in user space. - // Then we don't need to save the `sp_el1` to the taskctx. - unsafe { - core::arch::asm!( - " - mov sp, x1 - - // backup kernel tpidr_el0 - mrs x1, tpidr_el0 - msr tpidrro_el0, x1 - - ldp x11, x12, [x0, 33 * 8] - ldp x9, x10, [x0, 31 * 8] - msr sp_el0, x9 - msr tpidr_el0, x10 - msr elr_el1, x11 - msr spsr_el1, x12 - - ldr x30, [x0, 30 * 8] - ldp x28, x29, [x0, 28 * 8] - ldp x26, x27, [x0, 26 * 8] - ldp x24, x25, [x0, 24 * 8] - ldp x22, x23, [x0, 22 * 8] - ldp x20, x21, [x0, 20 * 8] - ldp x18, x19, [x0, 18 * 8] - ldp x16, x17, [x0, 16 * 8] - ldp x14, x15, [x0, 14 * 8] - ldp x12, x13, [x0, 12 * 8] - ldp x10, x11, [x0, 10 * 8] - ldp x8, x9, [x0, 8 * 8] - ldp x6, x7, [x0, 6 * 8] - ldp x4, x5, [x0, 4 * 8] - ldp x2, x3, [x0, 2 * 8] - ldp x0, x1, [x0] - eret", - in("x0") &self.0, - in("x1") kstack_top.as_usize() , - options(noreturn), - ) - } - } } impl core::ops::Deref for UspaceContext { @@ -112,7 +57,6 @@ use core::{ arch::naked_asm, mem::offset_of, ops::{Deref, DerefMut}, - ptr::addr_of, }; use crate::trap::{ExceptionKind, ReturnReason}; @@ -271,11 +215,8 @@ pub unsafe fn compare_and_dump_u64(addr1: usize, addr2: usize, num_words: usize) impl UserContext { pub fn run(&mut self) -> ReturnReason { debug!( - "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x}, el{}", - self.tf.elr, - self.sp_el1, - self.tf.usp, - CurrentEL.read(CurrentEL::EL) + "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x} ", + self.tf.elr, self.sp_el1, self.tf.usp, ); unsafe { enter_user(self); @@ -312,8 +253,8 @@ impl UserContext { r: [0u64; 31], usp: ustack_top.as_usize() as u64, // 假设 VirtAddr 有 as_u64 方法 tpidr: 0, - elr: entry as u64, // 用户入口地址 - spsr: 0 | (0b0000 << 4), // 可根据 EL 设置初值 // 0001 0000 1100 0111 0000 + elr: entry as u64, // 用户入口地址 + spsr: 0, // 默认初始化为 0 }, sp_el1: 0, // EL1 栈指针 } @@ -324,48 +265,48 @@ impl UserContext { unsafe extern "C" fn enter_user(_ctx: &mut UserContext) { naked_asm!( " - sub sp, sp, 12 * 8 - stp x29, x30, [sp,10 * 8] + // -- save kernel context -- + sub sp, sp, 12 * 8 + stp x29, x30, [sp, 10 * 8] stp x27, x28, [sp, 8 * 8] stp x25, x26, [sp, 6 * 8] stp x23, x24, [sp, 4 * 8] stp x21, x22, [sp, 2 * 8] - stp x19, x20, [sp, 2 * 0] + stp x19, x20, [sp] mov x8, sp - msr sp_el1, x8 - - str x8, [x0, {sp_el1}] + str x8, [x0, {sp_el1}] // save sp_el1 to ctx.sp_el1 // -- restore user context -- - + mov sp, x0 + mrs x8, tpidr_el0 msr tpidrro_el0, x8 - ldp x8, x9, [x0, {elr_el1}] + ldp x8, x9, [sp, {elr_el1}] msr elr_el1, x8 msr spsr_el1, x9 - ldp x8, x9, [x0, {sp_el0}] + ldp x8, x9, [sp, {sp_el0}] msr sp_el0, x8 msr tpidr_el0, x9 - ldr x30, [x0, 30 * 8] - ldp x28, x29, [x0, 28 * 8] - ldp x26, x27, [x0, 26 * 8] - ldp x24, x25, [x0, 24 * 8] - ldp x22, x23, [x0, 22 * 8] - ldp x20, x21, [x0, 20 * 8] - ldp x18, x19, [x0, 18 * 8] - ldp x16, x17, [x0, 16 * 8] - ldp x14, x15, [x0, 14 * 8] - ldp x12, x13, [x0, 12 * 8] - ldp x10, x11, [x0, 10 * 8] - ldp x8, x9, [x0, 8 * 8] - ldp x6, x7, [x0, 6 * 8] - ldp x4, x5, [x0, 4 * 8] - ldp x2, x3, [x0, 2 * 8] - ldp x0, x1, [x0] + ldr x30, [sp, 30 * 8] + ldp x28, x29, [sp, 28 * 8] + ldp x26, x27, [sp, 26 * 8] + ldp x24, x25, [sp, 24 * 8] + ldp x22, x23, [sp, 22 * 8] + ldp x20, x21, [sp, 20 * 8] + ldp x18, x19, [sp, 18 * 8] + ldp x16, x17, [sp, 16 * 8] + ldp x14, x15, [sp, 14 * 8] + ldp x12, x13, [sp, 12 * 8] + ldp x10, x11, [sp, 10 * 8] + ldp x8, x9, [sp, 8 * 8] + ldp x6, x7, [sp, 6 * 8] + ldp x4, x5, [sp, 4 * 8] + ldp x2, x3, [sp, 2 * 8] + ldp x0, x1, [sp] eret ", sp_el1 = const offset_of!(UserContext, sp_el1), @@ -373,3 +314,23 @@ unsafe extern "C" fn enter_user(_ctx: &mut UserContext) { sp_el0 = const offset_of!(TrapFrame, usp), ) } + +#[unsafe(no_mangle)] +#[unsafe(naked)] +pub unsafe extern "C" fn _user_trap_entry() -> ! { + naked_asm!( + " + ldr x8, [sp, {sp_el1}] // load ctx.sp_el1 to x8 + mov sp, x8 + ldp x19, x20, [sp] + ldp x21, x22, [sp, 2 * 8] + ldp x23, x24, [sp, 4 * 8] + ldp x25, x26, [sp, 6 * 8] + ldp x27, x28, [sp, 8 * 8] + ldp x29, x30, [sp, 10 * 8] + add sp, sp, 12 * 8 + ret + ", + sp_el1 = const offset_of!(UserContext, sp_el1), + ) +} From 3f283643f430d558e5bcfe0c372de5f957818475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 10:23:59 +0800 Subject: [PATCH 07/15] fix: aarch64 user entry and exit --- src/aarch64/trap.S | 11 +++++++---- src/aarch64/trap.rs | 6 ++++-- src/aarch64/uspace.rs | 10 ++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/aarch64/trap.S b/src/aarch64/trap.S index 72870aa..03b9057 100644 --- a/src/aarch64/trap.S +++ b/src/aarch64/trap.S @@ -1,5 +1,4 @@ .macro SAVE_REGS - sub sp, sp, {trapframe_size} stp x0, x1, [sp] stp x2, x3, [sp, 2 * 8] stp x4, x5, [sp, 4 * 8] @@ -65,6 +64,7 @@ .macro INVALID_EXCP, kind, source .p2align 7 + sub sp, sp, {trapframe_size} SAVE_REGS mov x0, sp mov x1, \kind @@ -73,9 +73,10 @@ b .Lexception_return .endm -.macro TASK_EXIT, kind, source +.macro TASK_EXIT, kind .p2align 7 SAVE_REGS + mov x0, \kind b _user_trap_entry .endm @@ -85,6 +86,7 @@ .macro HANDLE_SYNC, source .p2align 7 + sub sp, sp, {trapframe_size} SAVE_REGS mov x0, sp mov x1, \source @@ -94,6 +96,7 @@ .macro HANDLE_IRQ, source .p2align 7 + sub sp, sp, {trapframe_size} SAVE_REGS mov x0, sp mov x1, \source @@ -122,9 +125,9 @@ curr_el_spx_fiq: curr_el_spx_serror: INVALID_EXCP 3 1 lower_el_aarch64_sync: - TASK_EXIT 0 2 + TASK_EXIT {kind_sync} lower_el_aarch64_irq: - TASK_EXIT 1 2 + TASK_EXIT {kind_irq} lower_el_aarch64_fiq: INVALID_EXCP 2 2 lower_el_aarch64_serror: diff --git a/src/aarch64/trap.rs b/src/aarch64/trap.rs index a67c724..c003ae4 100644 --- a/src/aarch64/trap.rs +++ b/src/aarch64/trap.rs @@ -6,13 +6,15 @@ use crate::trap::PageFaultFlags; core::arch::global_asm!( include_str!("trap.S"), - trapframe_size = const core::mem::size_of::() + trapframe_size = const core::mem::size_of::(), + kind_irq = const TrapKind::Irq as u8, + kind_sync = const TrapKind::Synchronous as u8, ); #[repr(u8)] #[derive(Debug)] #[allow(dead_code)] -enum TrapKind { +pub(crate) enum TrapKind { Synchronous = 0, Irq = 1, Fiq = 2, diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index c5f4fc8..687c941 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -2,7 +2,7 @@ use memory_addr::VirtAddr; -use crate::TrapFrame; +use crate::{TrapFrame, aarch64::trap::TrapKind}; /// Context to enter user space. pub struct UspaceContext(TrapFrame); @@ -218,10 +218,8 @@ impl UserContext { "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x} ", self.tf.elr, self.sp_el1, self.tf.usp, ); - unsafe { - enter_user(self); - } - debug!("Returned from user space"); + let tp_kind = unsafe { _enter_user(self) }; + debug!("Returned from user space with TrapKind: {:?}", tp_kind); let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); @@ -262,7 +260,7 @@ impl UserContext { } #[unsafe(naked)] -unsafe extern "C" fn enter_user(_ctx: &mut UserContext) { +unsafe extern "C" fn _enter_user(_ctx: &mut UserContext) -> TrapKind { naked_asm!( " // -- save kernel context -- From 3d4a8ce922fea595a0abc780b9dec355a64f2107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 10:50:31 +0800 Subject: [PATCH 08/15] fix: irq --- src/aarch64/uspace.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 687c941..c4d1b8f 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -112,7 +112,7 @@ impl From for UserContext { } } -use aarch64_cpu::registers::{CurrentEL, ESR_EL1, FAR_EL1, Readable}; +use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; use page_table_entry::MappingFlags; fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { @@ -220,6 +220,12 @@ impl UserContext { ); let tp_kind = unsafe { _enter_user(self) }; debug!("Returned from user space with TrapKind: {:?}", tp_kind); + + if matches!(tp_kind, TrapKind::Irq) { + handle_trap!(IRQ, 0); + return ReturnReason::Interrupt; + } + let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); From 19937d92235a287e3d8607be4307e288de7e324d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 11:17:04 +0800 Subject: [PATCH 09/15] fix: exception --- src/aarch64/asm.rs | 33 ++++++++++++------ src/aarch64/trap.rs | 17 ++++----- src/aarch64/user_copy.S | 76 +++++++++++++++++++++++++++++++++++++++++ src/aarch64/uspace.rs | 35 +++++++++++-------- 4 files changed, 126 insertions(+), 35 deletions(-) create mode 100644 src/aarch64/user_copy.S diff --git a/src/aarch64/asm.rs b/src/aarch64/asm.rs index 327feff..aa54f1b 100644 --- a/src/aarch64/asm.rs +++ b/src/aarch64/asm.rs @@ -64,7 +64,8 @@ pub fn read_kernel_page_table() -> PhysAddr { /// Reads the current page table root register for user space (`TTBR0_EL1`). /// /// When the "arm-el2" feature is enabled, for user-mode programs, -/// virtualization is completely transparent to them, so there is no need to modify +/// virtualization is completely transparent to them, so there is no need to +/// modify /// /// Returns the physical address of the page table root. #[inline] @@ -88,13 +89,15 @@ pub fn read_user_page_table() -> PhysAddr { pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) { #[cfg(not(feature = "arm-el2"))] { - // kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff) + // kernel space page table use TTBR1 + // (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff) TTBR1_EL1.set(root_paddr.as_usize() as _); } #[cfg(feature = "arm-el2")] { - // kernel space page table at EL2 use TTBR0_EL2 (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff) + // kernel space page table at EL2 use TTBR0_EL2 + // (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff) TTBR0_EL2.set(root_paddr.as_usize() as _); } } @@ -102,7 +105,8 @@ pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) { /// Writes the register to update the current page table root for user space /// (`TTBR1_EL0`). /// When the "arm-el2" feature is enabled, for user-mode programs, -/// virtualization is completely transparent to them, so there is no need to modify +/// virtualization is completely transparent to them, so there is no need to +/// modify /// /// Note that the TLB is **NOT** flushed after this operation. /// @@ -202,9 +206,18 @@ pub fn enable_fp() { barrier::isb(barrier::SY); } -pub fn user_copy(_dst: *mut u8, _src: *const u8, _size: usize) -> usize { - info!( - "Copy user data!" - ); - 0 -} \ No newline at end of file +core::arch::global_asm!(include_str!("user_copy.S")); + +extern "C" { + /// Copy data from user space to kernel space safely. + /// + /// # Arguments + /// * `dst` - Destination pointer in kernel space + /// * `src` - Source pointer in user space + /// * `size` - Number of bytes to copy + /// + /// # Returns + /// * `0` - Success, all bytes copied + /// * `>0` - Number of bytes that could not be copied due to page fault + pub fn user_copy(dst: *mut u8, src: *const u8, size: usize) -> usize; +} diff --git a/src/aarch64/trap.rs b/src/aarch64/trap.rs index c003ae4..b5b1d0e 100644 --- a/src/aarch64/trap.rs +++ b/src/aarch64/trap.rs @@ -16,9 +16,9 @@ core::arch::global_asm!( #[allow(dead_code)] pub(crate) enum TrapKind { Synchronous = 0, - Irq = 1, - Fiq = 2, - SError = 3, + Irq = 1, + Fiq = 2, + SError = 3, } #[repr(u8)] @@ -56,14 +56,10 @@ fn handle_irq_exception(_tf: &mut TrapFrame, _source: TrapSource) { fn handle_sync_exception(tf: &mut TrapFrame, _source: TrapSource) { let esr = ESR_EL1.extract(); let iss = esr.read(ESR_EL1::ISS); - warn!("handle trap in current el!"); // crate::trap::pre_trap_callback(tf, source.is_from_user()); match esr.read_as_enum(ESR_EL1::EC) { #[cfg(feature = "uspace")] - Some(ESR_EL1::EC::Value::SVC64) => { - // Do Not handle syscall here - // tf.r[0] = crate::trap::handle_syscall(tf, tf.r[8] as usize) as u64; - } + Some(ESR_EL1::EC::Value::SVC64) => {} Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => handle_instruction_abort(tf, iss, true), Some(ESR_EL1::EC::Value::InstrAbortCurrentEL) => handle_instruction_abort(tf, iss, false), Some(ESR_EL1::EC::Value::DataAbortLowerEL) => handle_data_abort(tf, iss, true), @@ -86,7 +82,6 @@ fn handle_sync_exception(tf: &mut TrapFrame, _source: TrapSource) { // crate::trap::post_trap_callback(tf, source.is_from_user()); } - pub(crate) fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) { let mut access_flags = PageFaultFlags::EXECUTE; if is_user { @@ -99,7 +94,8 @@ pub(crate) fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) || !handle_trap!(PAGE_FAULT, vaddr, access_flags) { panic!( - "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} ({:?}):\n{:#x?}\n{}", + "Unhandled {} Instruction Abort @ {:#x}, fault_vaddr={:#x}, ESR={:#x} \ + ({:?}):\n{:#x?}\n{}", if is_user { "EL0" } else { "EL1" }, tf.elr, vaddr, @@ -140,4 +136,3 @@ fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) { ); } } - diff --git a/src/aarch64/user_copy.S b/src/aarch64/user_copy.S new file mode 100644 index 0000000..abb7eca --- /dev/null +++ b/src/aarch64/user_copy.S @@ -0,0 +1,76 @@ +// AArch64 user space safe memory copy +// Based on RISC-V implementation and optimized for AArch64 + +.section .text +.global user_copy +user_copy: + // x0 = dst, x1 = src, x2 = size + // Return: 0 on success, remaining bytes on fault + + // Quick exit for zero size + cbz x2, .Lsuccess + + // Save the end address for fault handling + add x3, x0, x2 // x3 = dst_end + mov x4, x2 // x4 = original_size (for fault calculation) + + // Use different strategies based on size + cmp x2, #64 + b.lo .Lbyte_copy + + // For larger copies, try to align and use word copy + // First align dst to 8-byte boundary + and x5, x0, #7 + cbz x5, .Laligned_copy + + // Copy bytes until dst is 8-byte aligned + sub x5, x2, x5 // remaining after alignment +.Lalign_loop: + ldrb w6, [x1], #1 + strb w6, [x0], #1 + tbnz x0, #0, .Lalign_loop + tbnz x0, #1, .Lalign_loop + tbnz x0, #2, .Lalign_loop + mov x2, x5 // update remaining size + +.Laligned_copy: + // Now dst is 8-byte aligned, do word copy + cmp x2, #8 + b.lo .Lbyte_copy + + // Unrolled 8-word (64-byte) copy loop + sub x5, x2, #64 +.Lword_loop: + ldp x6, x7, [x1], #16 + ldp x8, x9, [x1], #16 + ldp x10, x11, [x1], #16 + ldp x12, x13, [x1], #16 + stp x6, x7, [x0], #16 + stp x8, x9, [x0], #16 + stp x10, x11, [x0], #16 + stp x12, x13, [x0], #16 + subs x2, x2, #64 + cmp x2, #64 + b.hs .Lword_loop + + // Handle remaining words (8-byte chunks) +.Lword_remainder: + cmp x2, #8 + b.lo .Lbyte_copy + ldr x6, [x1], #8 + str x6, [x0], #8 + sub x2, x2, #8 + b .Lword_remainder + +.Lbyte_copy: + // Copy remaining bytes + cbz x2, .Lsuccess +.Lbyte_loop: + ldrb w6, [x1], #1 + strb w6, [x0], #1 + subs x2, x2, #1 + b.ne .Lbyte_loop + +.Lsuccess: + mov x0, #0 + ret \ No newline at end of file diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index c4d1b8f..05d24b6 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -1,5 +1,6 @@ //! Structures and functions for user space. +use aarch64_cpu::registers::ESR_EL1; use memory_addr::VirtAddr; use crate::{TrapFrame, aarch64::trap::TrapKind}; @@ -63,22 +64,21 @@ use crate::trap::{ExceptionKind, ReturnReason}; #[derive(Debug, Clone, Copy)] pub struct ExceptionInfo { - // pub e: E, + pub esr: u64, pub stval: usize, } impl ExceptionInfo { pub fn kind(&self) -> ExceptionKind { - // match self.e { - // E::Breakpoint => ExceptionKind::Breakpoint, - // E::IllegalInstruction => ExceptionKind::IllegalInstruction, - // E::InstructionMisaligned | E::LoadMisaligned | E::StoreMisaligned => { - // ExceptionKind::Misaligned - // } - // _ => ExceptionKind::Other, - // } - - ExceptionKind::Other + let esr: tock_registers::LocalRegisterCopy = + tock_registers::LocalRegisterCopy::new(self.esr); + match esr.read_as_enum(ESR_EL1::EC) { + Some(ESR_EL1::EC::Value::BreakpointLowerEL) => ExceptionKind::Breakpoint, + Some(ESR_EL1::EC::Value::IllegalExecutionState) => ExceptionKind::IllegalInstruction, + Some(ESR_EL1::EC::Value::PCAlignmentFault) + | Some(ESR_EL1::EC::Value::SPAlignmentFault) => ExceptionKind::Misaligned, + _ => ExceptionKind::Other, + } } } @@ -112,7 +112,7 @@ impl From for UserContext { } } -use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; +use aarch64_cpu::registers::{FAR_EL1, Readable}; use page_table_entry::MappingFlags; fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { @@ -231,13 +231,20 @@ impl UserContext { match esr.read_as_enum(ESR_EL1::EC) { Some(ESR_EL1::EC::Value::SVC64) => { - info!("task return because syscall ..."); + // info!("task return because syscall ..."); ReturnReason::Syscall } Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { - info!("task return because InstrAbortLowerEL ..."); handle_instruction_abort_lower(&self.tf, iss, true) } + Some(ESR_EL1::EC::Value::BreakpointLowerEL) + | Some(ESR_EL1::EC::Value::PCAlignmentFault) + | Some(ESR_EL1::EC::Value::SPAlignmentFault) => { + ReturnReason::Exception(ExceptionInfo { + esr: esr.get(), + stval: FAR_EL1.get() as usize, + }) + } Some(ESR_EL1::EC::Value::DataAbortLowerEL) => { info!("task return because DataAbortLowerEL ..."); handle_data_abort_lower(&self.tf, iss, true) From bb76db2573113d569490c46738ec449cccd498de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 16:45:50 +0800 Subject: [PATCH 10/15] fmt code --- src/aarch64/uspace.rs | 69 ++++++++----------------------------------- 1 file changed, 13 insertions(+), 56 deletions(-) diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 05d24b6..32300e4 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -1,9 +1,18 @@ //! Structures and functions for user space. +use core::{ + arch::naked_asm, + mem::offset_of, + ops::{Deref, DerefMut}, +}; use aarch64_cpu::registers::ESR_EL1; use memory_addr::VirtAddr; -use crate::{TrapFrame, aarch64::trap::TrapKind}; +use crate::{ + TrapFrame, + aarch64::trap::TrapKind, + trap::{ExceptionKind, ReturnReason}, +}; /// Context to enter user space. pub struct UspaceContext(TrapFrame); @@ -54,14 +63,6 @@ impl core::ops::DerefMut for UspaceContext { } } -use core::{ - arch::naked_asm, - mem::offset_of, - ops::{Deref, DerefMut}, -}; - -use crate::trap::{ExceptionKind, ReturnReason}; - #[derive(Debug, Clone, Copy)] pub struct ExceptionInfo { pub esr: u64, @@ -174,52 +175,10 @@ fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnRea } } -/// Compare two memory regions as u64 words, dump both if any difference found. -/// -/// # Safety -/// Caller must ensure both addr1 and addr2 are valid for `num_words * 8` bytes. -pub unsafe fn compare_and_dump_u64(addr1: usize, addr2: usize, num_words: usize) -> bool { - let ptr1 = addr1 as *const u64; - let ptr2 = addr2 as *const u64; - - let mut equal = true; - - for i in 0..num_words { - let val1 = *ptr1.add(i); - let val2 = *ptr2.add(i); - if val1 != val2 { - equal = false; - break; - } - } - - if !equal { - warn!("Memory regions differ, dumping contents:"); - - warn!("Region 1 at {:#x}:", addr1); - for i in 0..num_words { - let val = *ptr1.add(i); - warn!(" [{:02}] = {:#018x}", i, val); - } - - warn!("Region 2 at {:#x}:", addr2); - for i in 0..num_words { - let val = *ptr2.add(i); - warn!(" [{:02}] = {:#018x}", i, val); - } - } - - equal -} - impl UserContext { pub fn run(&mut self) -> ReturnReason { - debug!( - "UserContext::run: elr={:#x}, sp_el1={:#x}, usp={:#x} ", - self.tf.elr, self.sp_el1, self.tf.usp, - ); let tp_kind = unsafe { _enter_user(self) }; - debug!("Returned from user space with TrapKind: {:?}", tp_kind); + trace!("Returned from user space with TrapKind: {:?}", tp_kind); if matches!(tp_kind, TrapKind::Irq) { handle_trap!(IRQ, 0); @@ -230,14 +189,12 @@ impl UserContext { let iss = esr.read(ESR_EL1::ISS); match esr.read_as_enum(ESR_EL1::EC) { - Some(ESR_EL1::EC::Value::SVC64) => { - // info!("task return because syscall ..."); - ReturnReason::Syscall - } + Some(ESR_EL1::EC::Value::SVC64) => ReturnReason::Syscall, Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { handle_instruction_abort_lower(&self.tf, iss, true) } Some(ESR_EL1::EC::Value::BreakpointLowerEL) + | Some(ESR_EL1::EC::Value::IllegalExecutionState) | Some(ESR_EL1::EC::Value::PCAlignmentFault) | Some(ESR_EL1::EC::Value::SPAlignmentFault) => { ReturnReason::Exception(ExceptionInfo { From 5573554c5a1b2ca9eb6eb962b2da6605bfb89cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 16:59:43 +0800 Subject: [PATCH 11/15] fmt code --- src/aarch64/uspace.rs | 52 +------------------------------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index c81bf48..40b21b3 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -6,64 +6,14 @@ use core::{ }; use aarch64_cpu::registers::ESR_EL1; - use memory_addr::VirtAddr; use crate::{ - trap::{ExceptionKind, ReturnReason}, TrapFrame, aarch64::trap::TrapKind, + trap::{ExceptionKind, ReturnReason}, }; -/// Context to enter user space. -pub struct UserContext(TrapFrame); - -impl UserContext { - /// Creates an empty context with all registers set to zero. - pub const fn empty() -> Self { - Self(TrapFrame::new()) - } - - /// Creates a new context with the given entry point, user stack pointer, - /// and the argument. - pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self { - use aarch64_cpu::registers::SPSR_EL1; - let mut regs = [0; 31]; - regs[0] = arg0 as _; - Self(TrapFrame { - r: regs, - usp: ustack_top.as_usize() as _, - tpidr: 0, - elr: entry as _, - spsr: (SPSR_EL1::M::EL0t - + SPSR_EL1::D::Masked - + SPSR_EL1::A::Masked - + SPSR_EL1::I::Unmasked - + SPSR_EL1::F::Masked) - .value, - }) - } - - /// Creates a new context from the given [`TrapFrame`]. - pub const fn from(trap_frame: &TrapFrame) -> Self { - Self(*trap_frame) - } -} - -impl Deref for UserContext { - type Target = TrapFrame; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for UserContext { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - #[derive(Debug, Clone, Copy)] pub struct ExceptionInfo { pub esr: u64, From ae356c893394b6c2f33dfd228160a2cb131e4f5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Thu, 18 Sep 2025 17:08:11 +0800 Subject: [PATCH 12/15] fmt code --- src/trap.rs | 41 ++++------------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/src/trap.rs b/src/trap.rs index 74debef..31b9c13 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -2,12 +2,13 @@ use core::fmt::Debug; +pub use linkme::{ + distributed_slice as def_trap_handler, distributed_slice as register_trap_handler, +}; use memory_addr::VirtAddr; +pub use page_table_entry::MappingFlags as PageFaultFlags; pub use crate::TrapFrame; -pub use linkme::distributed_slice as def_trap_handler; -pub use linkme::distributed_slice as register_trap_handler; -pub use page_table_entry::MappingFlags as PageFaultFlags; /// A slice of IRQ handler functions. #[def_trap_handler] @@ -33,26 +34,6 @@ macro_rules! handle_trap { }} } - -#[derive(Debug, Clone, Copy)] -pub enum ExceptionSource { - CurrentSpEl0 = 0, - CurrentSpElx = 1, - LowerAarch64 = 2, - LowerAarch32 = 3, -} - -pub const fn excp_mask(kind: u8, source: ExceptionSource) -> u16 { - 1 << ((source as u8) * 4 + kind) -} - -// 用例 -pub const TASK_EXIT_0_1: u16 = excp_mask(0, ExceptionSource::CurrentSpElx); -pub const TASK_EXIT_1_1: u16 = excp_mask(1, ExceptionSource::CurrentSpElx); -pub const TASK_EXIT_0_2: u16 = excp_mask(0, ExceptionSource::LowerAarch64); -pub const TASK_EXIT_1_2: u16 = excp_mask(1, ExceptionSource::LowerAarch64); -// 0x10, 0x20, 0x100, 0x200 - #[cfg(feature = "uspace")] #[derive(Debug, Clone, Copy)] pub enum ReturnReason { @@ -63,20 +44,6 @@ pub enum ReturnReason { Exception(crate::uspace::ExceptionInfo), } -impl ReturnReason { - /// 从 task_in() 返回的 bitmask 解码 - pub fn from_mask(mask: u16) -> Self { - match mask { - TASK_EXIT_0_1 => ReturnReason::Syscall, // TASK_EXIT 0 1 - TASK_EXIT_1_1 => ReturnReason::Interrupt, // TASK_EXIT 1 1 - TASK_EXIT_0_2 => ReturnReason::Syscall, - TASK_EXIT_1_2 => ReturnReason::Interrupt, - _ => ReturnReason::Unknown, - } - } - -} - #[cfg(feature = "uspace")] pub enum ExceptionKind { Other, From f1db9022768310756cc32fc4bfeaa3337f0584d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Sep 2025 12:38:49 +0800 Subject: [PATCH 13/15] impl arg0 --- src/aarch64/uspace.rs | 116 +++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 40b21b3..229fdec 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -5,8 +5,9 @@ use core::{ ops::{Deref, DerefMut}, }; -use aarch64_cpu::registers::ESR_EL1; +use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; use memory_addr::VirtAddr; +use page_table_entry::MappingFlags; use crate::{ TrapFrame, @@ -41,6 +42,62 @@ pub struct UserContext { sp_el1: u64, } +impl UserContext { + pub fn run(&mut self) -> ReturnReason { + let tp_kind = unsafe { _enter_user(self) }; + trace!("Returned from user space with TrapKind: {:?}", tp_kind); + + if matches!(tp_kind, TrapKind::Irq) { + handle_trap!(IRQ, 0); + return ReturnReason::Interrupt; + } + + let esr = ESR_EL1.extract(); + let iss = esr.read(ESR_EL1::ISS); + + match esr.read_as_enum(ESR_EL1::EC) { + Some(ESR_EL1::EC::Value::SVC64) => ReturnReason::Syscall, + Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { + handle_instruction_abort_lower(&self.tf, iss, true) + } + Some(ESR_EL1::EC::Value::BreakpointLowerEL) + | Some(ESR_EL1::EC::Value::IllegalExecutionState) + | Some(ESR_EL1::EC::Value::PCAlignmentFault) + | Some(ESR_EL1::EC::Value::SPAlignmentFault) => { + ReturnReason::Exception(ExceptionInfo { + esr: esr.get(), + stval: FAR_EL1.get() as usize, + }) + } + Some(ESR_EL1::EC::Value::DataAbortLowerEL) => { + info!("task return because DataAbortLowerEL ..."); + handle_data_abort_lower(&self.tf, iss, true) + } + _ => ReturnReason::Unknown, + } + } + + pub fn new(entry: usize, ustack_top: VirtAddr, arg0: usize) -> Self { + info!( + "new ctx: entry={:#x}, ustack_top={:#x}", + entry, + ustack_top.as_usize() + ); + let mut r = [0u64; 31]; + r[0] = arg0 as u64; + Self { + tf: TrapFrame { + r, + usp: ustack_top.as_usize() as u64, // 假设 VirtAddr 有 as_u64 方法 + tpidr: 0, + elr: entry as u64, + spsr: 0, // recommend to set to 0 + }, + sp_el1: 0, // stack pointer for EL1, will be set in _enter_user + } + } +} + impl Deref for UserContext { type Target = TrapFrame; @@ -64,9 +121,6 @@ impl From for UserContext { } } -use aarch64_cpu::registers::{FAR_EL1, Readable}; -use page_table_entry::MappingFlags; - fn handle_instruction_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnReason { let mut access_flags = MappingFlags::EXECUTE; if is_user { @@ -126,60 +180,6 @@ fn handle_data_abort_lower(tf: &TrapFrame, iss: u64, is_user: bool) -> ReturnRea } } -impl UserContext { - pub fn run(&mut self) -> ReturnReason { - let tp_kind = unsafe { _enter_user(self) }; - trace!("Returned from user space with TrapKind: {:?}", tp_kind); - - if matches!(tp_kind, TrapKind::Irq) { - handle_trap!(IRQ, 0); - return ReturnReason::Interrupt; - } - - let esr = ESR_EL1.extract(); - let iss = esr.read(ESR_EL1::ISS); - - match esr.read_as_enum(ESR_EL1::EC) { - Some(ESR_EL1::EC::Value::SVC64) => ReturnReason::Syscall, - Some(ESR_EL1::EC::Value::InstrAbortLowerEL) => { - handle_instruction_abort_lower(&self.tf, iss, true) - } - Some(ESR_EL1::EC::Value::BreakpointLowerEL) - | Some(ESR_EL1::EC::Value::IllegalExecutionState) - | Some(ESR_EL1::EC::Value::PCAlignmentFault) - | Some(ESR_EL1::EC::Value::SPAlignmentFault) => { - ReturnReason::Exception(ExceptionInfo { - esr: esr.get(), - stval: FAR_EL1.get() as usize, - }) - } - Some(ESR_EL1::EC::Value::DataAbortLowerEL) => { - info!("task return because DataAbortLowerEL ..."); - handle_data_abort_lower(&self.tf, iss, true) - } - _ => ReturnReason::Unknown, - } - } - - pub fn new(entry: usize, ustack_top: VirtAddr, _arg0: usize) -> Self { - info!( - "new ctx: entry={:#x}, ustack_top={:#x}", - entry, - ustack_top.as_usize() - ); - Self { - tf: TrapFrame { - r: [0u64; 31], - usp: ustack_top.as_usize() as u64, // 假设 VirtAddr 有 as_u64 方法 - tpidr: 0, - elr: entry as u64, // 用户入口地址 - spsr: 0, // 默认初始化为 0 - }, - sp_el1: 0, // EL1 栈指针 - } - } -} - #[unsafe(naked)] unsafe extern "C" fn _enter_user(_ctx: &mut UserContext) -> TrapKind { naked_asm!( From e0ca0fc4a616513a63eaacf04af0fdebbdd0443e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= <34859362+ZR233@users.noreply.github.com> Date: Fri, 19 Sep 2025 12:50:46 +0800 Subject: [PATCH 14/15] Update src/aarch64/context.rs Co-authored-by: Asakura Mizu --- src/aarch64/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aarch64/context.rs b/src/aarch64/context.rs index 70ba1a9..82e08e4 100644 --- a/src/aarch64/context.rs +++ b/src/aarch64/context.rs @@ -124,7 +124,7 @@ impl TrapFrame { self.r[0] as _ } - // TODO: + /// Get the syscall number. pub const fn sysno(&self) -> usize { self.r[8] as usize } From 998dcc870c8b432d70158ef04325a2f391208c24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Fri, 19 Sep 2025 13:36:09 +0800 Subject: [PATCH 15/15] improve context --- src/aarch64/context.rs | 18 ++++++++++++------ src/aarch64/uspace.rs | 10 ++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/aarch64/context.rs b/src/aarch64/context.rs index 82e08e4..970d062 100644 --- a/src/aarch64/context.rs +++ b/src/aarch64/context.rs @@ -1,5 +1,5 @@ -use core::arch::naked_asm; -use core::fmt; +use core::{arch::naked_asm, fmt}; + use memory_addr::VirtAddr; /// Saved registers when a trap (exception) occurs. @@ -129,6 +129,11 @@ impl TrapFrame { self.r[8] as usize } + /// Sets the syscall number. + pub const fn set_sysno(&mut self, sysno: usize) { + self.r[8] = sysno as _; + } + /// Sets the return value register. pub const fn set_retval(&mut self, r0: usize) { self.r[0] = r0 as _; @@ -240,8 +245,9 @@ impl TaskContext { /// Changes the page table root in this context. /// - /// The hardware register for user page table root (`ttbr0_el1` for aarch64 in EL1) - /// will be updated to the next task's after [`Self::switch_to`]. + /// The hardware register for user page table root (`ttbr0_el1` for aarch64 + /// in EL1) will be updated to the next task's after + /// [`Self::switch_to`]. #[cfg(feature = "uspace")] pub fn set_page_table_root(&mut self, ttbr0_el1: memory_addr::PhysAddr) { self.ttbr0_el1 = ttbr0_el1; @@ -249,8 +255,8 @@ impl TaskContext { /// Switches to another task. /// - /// It first saves the current task's context from CPU to this place, and then - /// restores the next task's context from `next_ctx` to CPU. + /// It first saves the current task's context from CPU to this place, and + /// then restores the next task's context from `next_ctx` to CPU. pub fn switch_to(&mut self, next_ctx: &Self) { #[cfg(feature = "tls")] { diff --git a/src/aarch64/uspace.rs b/src/aarch64/uspace.rs index 229fdec..76807b7 100644 --- a/src/aarch64/uspace.rs +++ b/src/aarch64/uspace.rs @@ -8,6 +8,7 @@ use core::{ use aarch64_cpu::registers::{ESR_EL1, FAR_EL1, Readable}; use memory_addr::VirtAddr; use page_table_entry::MappingFlags; +use tock_registers::LocalRegisterCopy; use crate::{ TrapFrame, @@ -17,15 +18,13 @@ use crate::{ #[derive(Debug, Clone, Copy)] pub struct ExceptionInfo { - pub esr: u64, + pub esr: LocalRegisterCopy, pub stval: usize, } impl ExceptionInfo { pub fn kind(&self) -> ExceptionKind { - let esr: tock_registers::LocalRegisterCopy = - tock_registers::LocalRegisterCopy::new(self.esr); - match esr.read_as_enum(ESR_EL1::EC) { + match self.esr.read_as_enum(ESR_EL1::EC) { Some(ESR_EL1::EC::Value::BreakpointLowerEL) => ExceptionKind::Breakpoint, Some(ESR_EL1::EC::Value::IllegalExecutionState) => ExceptionKind::IllegalInstruction, Some(ESR_EL1::EC::Value::PCAlignmentFault) @@ -45,7 +44,6 @@ pub struct UserContext { impl UserContext { pub fn run(&mut self) -> ReturnReason { let tp_kind = unsafe { _enter_user(self) }; - trace!("Returned from user space with TrapKind: {:?}", tp_kind); if matches!(tp_kind, TrapKind::Irq) { handle_trap!(IRQ, 0); @@ -65,7 +63,7 @@ impl UserContext { | Some(ESR_EL1::EC::Value::PCAlignmentFault) | Some(ESR_EL1::EC::Value::SPAlignmentFault) => { ReturnReason::Exception(ExceptionInfo { - esr: esr.get(), + esr, stval: FAR_EL1.get() as usize, }) }