Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guoweikang/aarch64 1 #10

Merged
merged 6 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading