Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
95adf96
增加对 Loongarch64 架构的支持,添加上下文、宏和异常处理功能
SiyuanSun0736 Apr 28, 2025
03c10fa
更新 .gitignore 文件以包含 oscamp-ci 目录,修改 Makefile 以简化 run 目标
SiyuanSun0736 Apr 28, 2025
4f8a7cb
修复调试命令中的函数名,增强数据异常处理的调试信息,更新启动代码以支持不同架构,调整 pflash 地址常量,更新 Rust 工具链版本
SiyuanSun0736 May 7, 2025
58d514b
增强对不同架构的支持,更新 Makefile 和汇编代码以适应架构变化,简化系统调用实现
SiyuanSun0736 May 8, 2025
99526da
增加对系统调用参数的支持,扩展 UspaceContext 的构造函数以适应不同架构,更新主函数以正确初始化用户任务
SiyuanSun0736 May 8, 2025
7b1e966
优化 Makefile 中的构建命令顺序,确保正确传递架构参数;修复 skernel 中的汇编代码格式,增强可读性
SiyuanSun0736 May 8, 2025
5660c2f
修复 AArch64 系统调用实现,确保正确处理栈操作和系统调用号
SiyuanSun0736 May 17, 2025
0dd05d6
增强 AArch64 系统调用实现,修正栈操作并添加用户任务生成的调试信息
SiyuanSun0736 May 17, 2025
b7ae169
增强 AArch64 任务指针缓存功能,添加调试信息以提高可追踪性
SiyuanSun0736 May 17, 2025
817404a
在 Cargo.toml 中添加 axlog 依赖,并在 task.rs 中增加调试信息以增强任务管理的可追踪性
SiyuanSun0736 May 17, 2025
027efdd
在 cpu.rs 中添加调试信息以输出 SP_EL0 的值;在 api.rs 中记录任务退出时的退出代码
SiyuanSun0736 May 17, 2025
9f8b70b
在 trap.S 中添加对用户空间的信任恢复逻辑;在 trap.rs 中更新全局汇编以包含缓存当前任务指针的符号
SiyuanSun0736 May 17, 2025
32936e4
在 Cargo.toml 中添加 axlog 依赖;在 alloc.rs 中增加调试信息以跟踪页面故障处理;在多个 Makefile 中添…
SiyuanSun0736 May 17, 2025
b71be0b
在 trap.rs 中处理 Trapped FP 异常并增加调试信息;在 loader.rs 中添加加载 ELF 头信息的调试输出;在 s…
SiyuanSun0736 May 23, 2025
78219dd
移除多个文件中的调试输出,包括 axlog 的打印语句,以清理代码并提高可读性
SiyuanSun0736 May 23, 2025
5cf0bb4
Merge remote-tracking branch 'upstream/main'
SiyuanSun0736 May 23, 2025
cbe262b
移除 .gitignore 中的 oscamp-ci 目录,以清理不必要的忽略项
SiyuanSun0736 May 23, 2025
927db33
fix u_4
SiyuanSun0736 May 24, 2025
46c6b9d
fix m_3_1
SiyuanSun0736 May 24, 2025
73dc132
modify mk_pflash using argument
SiyuanSun0736 May 25, 2025
d624d5e
fix m_1_1
SiyuanSun0736 May 25, 2025
19c8a86
Submit the Dockerfile and instructions for its use.
SiyuanSun0736 May 25, 2025
cb8bfb2
fix util.mk and force build payload
SiyuanSun0736 May 26, 2025
223150e
try modify ci
SiyuanSun0736 May 26, 2025
6dc5c68
fix ci
SiyuanSun0736 May 26, 2025
a362dc7
test ci
SiyuanSun0736 May 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arceos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ members = [
"exercises/sys_map",
"exercises/simple_hv",
"exercises/ramfs_rename",

"examples/helloworld",
"examples/httpserver",
]

[workspace.package]
Expand Down
4 changes: 2 additions & 2 deletions arceos/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ debug: build
sleep 1
$(GDB) $(OUT_ELF) \
-ex 'target remote localhost:1234' \
-ex 'b rust_entry' \
-ex 'b rust_main' \
-ex 'continue' \
-ex 'disp /16i $$pc'

Expand Down Expand Up @@ -223,7 +223,7 @@ pflash_img:
$(call mk_pflash,$(PFLASH_IMG))

payload:
@make -C ./payload
@make ARCH=$(ARCH) -C ./payload

clean: clean_c
rm -rf $(APP)/*.bin $(APP)/*.elf
Expand Down
175 changes: 171 additions & 4 deletions arceos/modules/axhal/src/arch/aarch64/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,149 @@ pub struct TrapFrame {
pub spsr: u64,
}

impl TrapFrame {
/// Gets the 0th syscall argument.
pub const fn arg0(&self) -> usize {
self.r[0] as _
}

/// Gets the 1st syscall argument.
pub const fn arg1(&self) -> usize {
self.r[1] as _
}

/// Gets the 2nd syscall argument.
pub const fn arg2(&self) -> usize {
self.r[2] as _
}

/// Gets the 3rd syscall argument.
pub const fn arg3(&self) -> usize {
self.r[3] as _
}

/// Gets the 4th syscall argument.
pub const fn arg4(&self) -> usize {
self.r[4] as _
}

/// Gets the 5th syscall argument.
pub const fn arg5(&self) -> usize {
self.r[5] as _
}
}

/// Context to enter user space.
#[cfg(feature = "uspace")]
pub struct UspaceContext(TrapFrame);

#[cfg(feature = "uspace")]
impl UspaceContext {
/// Creates an empty context with all registers set to zero.
pub const fn empty() -> Self {
unsafe { core::mem::MaybeUninit::zeroed().assume_init() }
}

/// 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 _,
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)
}

/// Gets the instruction pointer.
pub const fn get_ip(&self) -> usize {
self.0.elr as _
}

/// Gets the stack pointer.
pub const fn get_sp(&self) -> usize {
self.0.usp as _
}

/// Sets the instruction pointer.
pub const fn set_ip(&mut self, pc: usize) {
self.0.elr = pc as _;
}

/// Sets the stack pointer.
pub const fn set_sp(&mut self, sp: usize) {
self.0.usp = sp as _;
}

/// Sets the return value register.
pub const fn set_retval(&mut self, r0: usize) {
self.0.r[0] = r0 as _;
}

/// 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.
#[inline(never)]
#[unsafe(no_mangle)]
pub unsafe fn enter_uspace(&self, kstack_top: VirtAddr) -> ! {
super::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
ldp x30, x9, [x0, 30 * 8]
ldp x10, x11, [x0, 32 * 8]
msr sp_el0, x9
msr elr_el1, x10
msr spsr_el1, x11

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),
)
}
}
}

/// FP & SIMD registers.
#[repr(C, align(16))]
#[derive(Debug, Default)]
Expand Down Expand Up @@ -47,7 +190,7 @@ impl FpState {
/// and the next task restores its context from memory to CPU.
#[allow(missing_docs)]
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct TaskContext {
pub sp: u64,
pub tpidr_el0: u64,
Expand All @@ -63,31 +206,55 @@ pub struct TaskContext {
pub r28: u64,
pub r29: u64,
pub lr: u64, // r30
/// The `ttbr0_el1` register value, i.e., the page table root.
#[cfg(feature = "uspace")]
pub ttbr0_el1: memory_addr::PhysAddr,
#[cfg(feature = "fp_simd")]
pub fp_state: FpState,
}

impl TaskContext {
/// Creates a new default context for a new task.
pub const fn new() -> Self {
unsafe { core::mem::MaybeUninit::zeroed().assume_init() }
/// Creates a dummy context for a new task.
///
/// Note the context is not initialized, it will be filled by [`switch_to`]
/// (for initial tasks) and [`init`] (for regular tasks) methods.
///
/// [`init`]: TaskContext::init
/// [`switch_to`]: TaskContext::switch_to
pub fn new() -> Self {
Self::default()
}

/// Initializes the context for a new task, with the given entry point and
/// kernel stack.
pub fn init(&mut self, entry: usize, kstack_top: VirtAddr, tls_area: VirtAddr) {
self.sp = kstack_top.as_usize() as u64;
self.lr = entry as u64;
// When under `uspace` feature, kernel will not use this register.
self.tpidr_el0 = tls_area.as_usize() as u64;
}

/// Changes the page table root for user space (`ttbr0_el1` register for aarch64 in el1 level).
///
/// If not set, it means that this task is a kernel task and only `ttbr1_el1` register will be used.
#[cfg(feature = "uspace")]
pub fn set_page_table_root(&mut self, ttbr0_el1: memory_addr::PhysAddr) {
self.ttbr0_el1 = ttbr0_el1;
}

/// 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.
pub fn switch_to(&mut self, next_ctx: &Self) {
#[cfg(feature = "fp_simd")]
self.fp_state.switch_to(&next_ctx.fp_state);
#[cfg(feature = "uspace")]
{
if self.ttbr0_el1 != next_ctx.ttbr0_el1 {
unsafe { super::write_page_table_root0(next_ctx.ttbr0_el1) };
}
}
unsafe { context_switch(self, next_ctx) }
}
}
Expand Down
17 changes: 16 additions & 1 deletion arceos/modules/axhal/src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
mod context;
pub(crate) mod trap;

#[cfg(target_os = "none")]
mod trap;

use core::arch::asm;

use aarch64_cpu::registers::{DAIF, TPIDR_EL0, TTBR0_EL1, TTBR1_EL1, VBAR_EL1};
use memory_addr::{PhysAddr, VirtAddr};
use tock_registers::interfaces::{Readable, Writeable};

#[cfg(feature = "uspace")]
pub use self::context::UspaceContext;
pub use self::context::{FpState, TaskContext, TrapFrame};

/// Allows the current CPU to respond to interrupts.
Expand Down Expand Up @@ -135,3 +139,14 @@ pub fn read_thread_pointer() -> usize {
pub unsafe fn write_thread_pointer(tpidr_el0: usize) {
TPIDR_EL0.set(tpidr_el0 as _)
}

/// Initializes CPU states on the current CPU.
///
/// On AArch64, it sets the exception vector base address (`VBAR_EL1`) and `TTBR0_EL1`.
pub fn cpu_init() {
unsafe extern "C" {
fn exception_vector_base();
}
set_exception_vector_base(exception_vector_base as usize);
unsafe { write_page_table_root0(0.into()) }; // disable low address access in EL1
}
5 changes: 5 additions & 0 deletions arceos/modules/axhal/src/arch/aarch64/trap.S
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
mrs x11, spsr_el1
stp x30, x9, [sp, 30 * 8]
stp x10, x11, [sp, 32 * 8]

# We may have interrupted userspace, or a guest, or exit-from or
# return-to either of those. So we can't trust sp_el0, and need to
# restore it.
bl {cache_current_task_ptr}
.endm

.macro RESTORE_REGS
Expand Down
10 changes: 8 additions & 2 deletions arceos/modules/axhal/src/arch/aarch64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use tock_registers::interfaces::Readable;

use super::TrapFrame;

global_asm!(include_str!("trap.S"));
global_asm!(include_str!("trap.S"), cache_current_task_ptr = sym crate::cpu::cache_current_task_ptr);

#[repr(u8)]
#[derive(Debug)]
Expand Down Expand Up @@ -65,6 +65,7 @@ fn handle_instruction_abort(tf: &TrapFrame, iss: u64, is_user: bool) {
}

fn handle_data_abort(tf: &TrapFrame, iss: u64, is_user: bool) {
debug!("ISS={:#x} tf={:#x?} is_user={}", iss, tf, is_user);
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 {
Expand Down Expand Up @@ -98,13 +99,18 @@ fn handle_sync_exception(tf: &mut TrapFrame) {
let esr = ESR_EL1.extract();
let iss = esr.read(ESR_EL1::ISS);
match esr.read_as_enum(ESR_EL1::EC) {
#[cfg(feature = "uspace")]
Some(ESR_EL1::EC::Value::SVC64) => {
warn!("No syscall is supported currently!");
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::TrappedFP) => {
debug!("Trapped FP @ {:#x} ", tf.elr);
tf.elr += 4;
}
Some(ESR_EL1::EC::Value::Brk64) => {
debug!("BRK #{:#x} @ {:#x} ", iss, tf.elr);
tf.elr += 4;
Expand Down
Loading
Loading