Skip to content

Commit

Permalink
Merge pull request #10 from guoweikang/guoweikang/aarch64_1
Browse files Browse the repository at this point in the history
Guoweikang/aarch64 1
  • Loading branch information
elliott10 authored Feb 26, 2024
2 parents c64b61a + 15408e8 commit 0d9f815
Show file tree
Hide file tree
Showing 23 changed files with 255 additions and 134 deletions.
2 changes: 1 addition & 1 deletion modules/axhal/src/arch/aarch64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,5 @@ fn handle_sync_exception(tf: &mut TrapFrame) {

#[no_mangle]
fn handle_irq_exception(_tf: &TrapFrame) {
crate::trap::handle_irq_extern(0)
crate::trap::handle_irq_extern(0, false)
}
65 changes: 64 additions & 1 deletion modules/axhal/src/arch/riscv/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,73 @@ pub struct TrapFrame {
pub fs: [usize; 2],
}

// 实现一个从 *mut MyType 的转换
impl From<*mut TrapFrame> for TrapFrame {
fn from(ptr: *mut TrapFrame) -> Self {
unsafe {
*ptr
}
}
}

impl TrapFrame {
fn set_user_sp(&mut self, user_sp: usize) {
pub fn set_user_sp(&mut self, user_sp: usize) {
self.regs.sp = user_sp;
}

pub fn sp(&mut self) -> usize {
self.regs.sp
}

pub unsafe fn sp_from_raw(ptr: *mut TrapFrame) -> usize {
(*ptr).regs.sp
}

pub unsafe fn pc_from_raw(ptr: *mut TrapFrame) -> usize {
(*ptr).sepc
}

pub fn pc(&mut self) -> usize {
self.sepc
}

pub fn set_pc(&mut self, pc: usize) {
self.sepc = pc;
}

pub unsafe fn set_pc_from_raw(ptr: *mut TrapFrame, pc: usize) {
(*ptr).sepc = pc;
}

pub fn set_tls(&mut self, tls: usize) {
self.regs.tp = tls;
}

#[cfg(feature = "monolithic")]
pub fn set_ret_code(&mut self, ret: usize) {
self.regs.a0 = ret;
}

pub fn set_param0(&mut self, param: usize) {
self.regs.a0 = param;
}

pub fn set_param1(&mut self, param: usize) {
self.regs.a1 = param;
}

pub fn set_param2(&mut self, param: usize) {
self.regs.a2 = param;
}

pub unsafe fn ret_from_raw(ptr: *mut TrapFrame) -> usize {
(*ptr).regs.a0
}

pub fn set_lr(&mut self, param: usize) {
self.regs.ra = param;
}

/// 用于第一次进入应用程序时的初始化
pub fn app_init_context(app_entry: usize, user_sp: usize) -> Self {
let sstatus = sstatus::read();
Expand Down
11 changes: 11 additions & 0 deletions modules/axhal/src/arch/riscv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ mod macros;
mod context;
mod trap;

#[cfg(feature = "monolithic")]
pub use trap::first_into_user;
pub use self::context::{GeneralRegisters, TaskContext, TrapFrame};
use memory_addr::{PhysAddr, VirtAddr};
use riscv::asm;
use riscv::register::{satp, sstatus, stvec};

extern "C" {
fn __copy(frame_address: *mut TrapFrame, kernel_base: usize);
}

pub unsafe fn copy_trap_frame(frame_address: *mut TrapFrame, kernel_base: usize) {
__copy(frame_address, kernel_base)
}

/// Allows the current CPU to respond to interrupts.
#[inline]
pub fn enable_irqs() {
Expand Down Expand Up @@ -63,6 +73,7 @@ pub unsafe fn write_page_table_root(root_paddr: PhysAddr) {
asm::sfence_vma_all();
}
}
pub use self::write_page_table_root as write_page_table_root0;

/// Flushes the TLB.
///
Expand Down
20 changes: 20 additions & 0 deletions modules/axhal/src/arch/riscv/trap.S
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,23 @@ trap_vector_base:
call riscv_trap_handler
RESTORE_REGS 1
sret

.altmacro
.macro COPY n
ld t2, (\n)*8(a0)
sd t2, (\n)*8(a1)
.endm

.section .text
.globl __copy
__copy:
# __copy(
# frame_address: *const TrapFrame,
# kernel_base: *mut T
# )
.set n, 0
.rept 33
COPY %n
.set n, n + 1
.endr
ret
61 changes: 60 additions & 1 deletion modules/axhal/src/arch/riscv/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,65 @@ fn handle_breakpoint(sepc: &mut usize) {
*sepc += 2
}

#[no_mangle]
#[cfg(feature = "monolithic")]
/// 手动进入用户态
///
/// 1. 将对应trap上下文压入内核栈
/// 2. 返回用户态
///
/// args:
///
/// 1. kernel_sp:内核栈顶
///
/// 2. frame_base:对应即将压入内核栈的trap上下文的地址
pub fn first_into_user(kernel_sp: usize, frame_base: usize) -> ! {
use crate::arch::disable_irqs;

let trap_frame_size = core::mem::size_of::<TrapFrame>();
let kernel_base = kernel_sp - trap_frame_size;
// 在保证将寄存器都存储好之后,再开启中断
// 否则此时会因为写入csr寄存器过程中出现中断,导致出现异常
disable_irqs();
// 在内核态中,tp寄存器存储的是当前任务的CPU ID
// 而当从内核态进入到用户态时,会将tp寄存器的值先存储在内核栈上,即把该任务对应的CPU ID存储在内核栈上
// 然后将tp寄存器的值改为对应线程的tls指针的值
// 因此在用户态中,tp寄存器存储的值是线程的tls指针的值
// 而当从用户态进入到内核态时,会先将内核栈上的值读取到某一个中间寄存器t0中,然后将tp的值存入内核栈
// 然后再将t0的值赋给tp,因此此时tp的值是当前任务的CPU ID
// 对应实现在axhal/src/arch/riscv/trap.S中
unsafe {
riscv::asm::sfence_vma_all();
core::arch::asm!(
r"
mv sp, {frame_base}
.short 0x2432 // fld fs0,264(sp)
.short 0x24d2 // fld fs1,272(sp)
mv t1, {kernel_base}
LDR t0, sp, 2
STR gp, t1, 2
mv gp, t0
LDR t0, sp, 3
STR tp, t1, 3 // save supervisor tp,注意是存储到内核栈上而不是sp中,此时存储的应该是当前运行的CPU的ID
mv tp, t0 // tp:本来存储的是CPU ID,在这个时候变成了对应线程的TLS 指针
csrw sscratch, {kernel_sp} // put supervisor sp to scratch
LDR t0, sp, 31
LDR t1, sp, 32
csrw sepc, t0
csrw sstatus, t1
POP_GENERAL_REGS
LDR sp, sp, 1
sret
",
frame_base = in(reg) frame_base,
kernel_sp = in(reg) kernel_sp,
kernel_base = in(reg) kernel_base,
);
};
core::panic!("already in user mode!")
}


#[no_mangle]
#[allow(unused)]
fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) {
Expand All @@ -41,7 +100,7 @@ fn riscv_trap_handler(tf: &mut TrapFrame, from_user: bool) {
axfs_ramfs::INTERRUPT.lock().record(scause.code());
match scause.cause() {
Trap::Exception(E::Breakpoint) => handle_breakpoint(&mut tf.sepc),
Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits()),
Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits(), from_user),
#[cfg(feature = "monolithic")]
Trap::Exception(E::UserEnvCall) => {
enable_irqs();
Expand Down
2 changes: 2 additions & 0 deletions modules/axhal/src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ pub unsafe fn write_page_table_root(root_paddr: PhysAddr) {
}
}

pub use self::write_page_table_root as write_page_table_root0;

/// Flushes the TLB.
///
/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
Expand Down
2 changes: 1 addition & 1 deletion modules/axhal/src/arch/x86_64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn x86_trap_handler(tf: &TrapFrame) {
tf.rip, tf.error_code, tf
);
}
IRQ_VECTOR_START..=IRQ_VECTOR_END => crate::trap::handle_irq_extern(tf.vector as _),
IRQ_VECTOR_START..=IRQ_VECTOR_END => crate::trap::handle_irq_extern(tf.vector as _, false),
_ => {
panic!(
"Unhandled exception {} (error_code = {:#x}) @ {:#x}:\n{:#x?}",
Expand Down
6 changes: 3 additions & 3 deletions modules/axhal/src/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use page_table_entry::MappingFlags;
#[def_interface]
pub trait TrapHandler {
/// Handles interrupt requests for the given IRQ number.
fn handle_irq(irq_num: usize);
fn handle_irq(irq_num: usize, from_user: bool);
// more e.g.: handle_page_fault();

// 需要分离用户态使用
Expand All @@ -30,8 +30,8 @@ pub trait TrapHandler {

/// Call the external IRQ handler.
#[allow(dead_code)]
pub(crate) fn handle_irq_extern(irq_num: usize) {
call_interface!(TrapHandler::handle_irq, irq_num);
pub(crate) fn handle_irq_extern(irq_num: usize, from_user: bool) {
call_interface!(TrapHandler::handle_irq, irq_num, from_user);
}

#[allow(dead_code)]
Expand Down
6 changes: 2 additions & 4 deletions modules/axmem/src/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use axhal::{
};
use axio::{Seek, SeekFrom};
use core::ptr::copy_nonoverlapping;
use riscv::asm::sfence_vma;

use crate::MemBackend;

Expand Down Expand Up @@ -157,9 +156,8 @@ impl MapArea {
self.flags,
)
.expect("Map in page fault handler failed");
unsafe {
sfence_vma(0, addr.align_down_4k().into());
}

axhal::arch::flush_tlb(addr.align_down_4k().into());
self.pages[page_index] = Some(page);
true
}
Expand Down
12 changes: 4 additions & 8 deletions modules/axmem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use core::{
sync::atomic::{AtomicI32, Ordering},
};
use page_table_entry::GenericPTE;
use riscv::asm::sfence_vma_all;
use shared::SharedMem;
use spinlock::SpinNoIrq;
#[macro_use]
Expand Down Expand Up @@ -479,7 +478,7 @@ impl MemorySet {

self.new_region(start, size, flags, None, backend);

unsafe { riscv::asm::sfence_vma_all() };
axhal::arch::flush_tlb(None);

start.as_usize() as isize
} else {
Expand Down Expand Up @@ -593,9 +592,7 @@ impl MemorySet {

assert!(self.owned_mem.insert(area.vaddr.into(), area).is_none());
}
unsafe {
sfence_vma_all();
}
axhal::arch::flush_tlb(None);
}

/// It will map newly allocated page in the page table. You need to flush TLB after this.
Expand All @@ -613,9 +610,8 @@ impl MemorySet {
}
None => {
error!(
"Page fault address {:?} not found in memory set sepc: {:X?}",
addr,
riscv::register::sepc::read()
"Page fault address {:?} not found in memory set ",
addr
);
Err(AxError::BadAddress)
}
Expand Down
2 changes: 1 addition & 1 deletion modules/axprocess/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ pub fn handle_page_fault(addr: VirtAddr, flags: MappingFlags) {
.handle_page_fault(addr, flags)
.is_ok()
{
unsafe { riscv::asm::sfence_vma_all() };
axhal::arch::flush_tlb(None);
} else {
#[cfg(feature = "signal")]
let _ = send_signal_to_thread(current().id().as_u64() as isize, SignalNo::SIGSEGV as isize);
Expand Down
20 changes: 9 additions & 11 deletions modules/axprocess/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use alloc::vec::Vec;
use alloc::{collections::BTreeMap, string::String};
use axerrno::{AxError, AxResult};
use axfs::api::{FileIO, OpenFlags};
use axhal::arch::{write_page_table_root, TrapFrame};
use axhal::arch::{write_page_table_root0, TrapFrame};
use axhal::mem::{phys_to_virt, VirtAddr};
use axhal::KERNEL_PROCESS_ID;
use axlog::{debug, error};
Expand Down Expand Up @@ -153,7 +153,8 @@ impl Process {
let page_table_token = memory_set.page_table_token();
if page_table_token != 0 {
unsafe {
write_page_table_root(page_table_token.into());
write_page_table_root0(page_table_token.into());
#[cfg(target_arch = "riscv64")]
riscv::register::sstatus::set_sum();
};
}
Expand Down Expand Up @@ -252,9 +253,7 @@ impl Process {
// 不是直接删除原有地址空间,否则构建成本较高。
self.memory_set.lock().unmap_user_areas();
// 清空用户堆,重置堆顶
unsafe {
riscv::asm::sfence_vma_all();
}
axhal::arch::flush_tlb(None);

// 关闭 `CLOEXEC` 的文件
// inner.fd_manager.close_on_exec();
Expand Down Expand Up @@ -295,10 +294,8 @@ impl Process {
self.memory_set.lock().page_table_token()
};
if page_table_token != 0 {
// axhal::arch::write_page_table_root(page_table_token.into());
unsafe {
write_page_table_root(page_table_token.into());
riscv::asm::sfence_vma_all();
write_page_table_root0(page_table_token.into());
};
// 清空用户堆,重置堆顶
}
Expand Down Expand Up @@ -524,16 +521,17 @@ impl Process {
let mut trap_frame = unsafe { *(current_task.get_first_trap_frame()) }.clone();
drop(current_task);
// 新开的进程/线程返回值为0
trap_frame.regs.a0 = 0;
trap_frame.set_ret_code(0);
if flags.contains(CloneFlags::CLONE_SETTLS) {
trap_frame.regs.tp = tls;
trap_frame.set_tls(tls);
}

// 设置用户栈
// 若给定了用户栈,则使用给定的用户栈
// 若没有给定用户栈,则使用当前用户栈
// 没有给定用户栈的时候,只能是共享了地址空间,且原先调用clone的有用户栈,此时已经在之前的trap clone时复制了
if let Some(stack) = stack {
trap_frame.regs.sp = stack;
trap_frame.set_user_sp(stack);
// info!(
// "New user stack: sepc:{:X}, stack:{:X}",
// trap_frame.sepc, trap_frame.regs.sp
Expand Down
Loading

0 comments on commit 0d9f815

Please sign in to comment.