Skip to content

Commit

Permalink
feat(riscv): riscv下能够运行hello world用户程序
Browse files Browse the repository at this point in the history
  • Loading branch information
fslongjin committed Apr 25, 2024
1 parent 40348dd commit abdf4ce
Show file tree
Hide file tree
Showing 33 changed files with 411 additions and 104 deletions.
2 changes: 1 addition & 1 deletion kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ x86_64 = "=0.14.10"

# target为riscv64时,使用下面的依赖
[target.'cfg(target_arch = "riscv64")'.dependencies]
riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", revision = "cc4d3ea82a", features = [ "s-mode" ] }
riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", rev = "4241a97", features = [ "s-mode" ] }
sbi-rt = { version = "=0.0.3", features = ["legacy"] }


Expand Down
2 changes: 2 additions & 0 deletions kernel/src/arch/riscv64/driver/of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use system_error::SystemError;
use crate::{
driver::open_firmware::fdt::OpenFirmwareFdtDriver,
init::boot_params,
kdebug,
libs::align::page_align_up,
mm::{mmio_buddy::mmio_pool, MemoryManagementArch, PhysAddr},
};
Expand All @@ -28,6 +29,7 @@ impl OpenFirmwareFdtDriver {

// drop the boot params guard in order to avoid deadlock
drop(bp_guard);
kdebug!("map_fdt: map fdt to {:?}, size: {}", map_paddr, map_size);
mmio_guard.map_phys(map_paddr, map_size)?;
let mut bp_guard = boot_params().write();
let vaddr = mmio_guard.vaddr() + offset;
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/arch/riscv64/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub fn early_setup_arch() -> Result<(), SystemError> {
arch_boot_params_guard.arch.fdt_paddr = fdt_paddr;
arch_boot_params_guard.arch.fdt_size = fdt.total_size();
arch_boot_params_guard.arch.boot_hartid = ProcessorId::new(hartid);

kdebug!("fdt_paddr: {:?}, fdt_size: {}", fdt_paddr, fdt.total_size());
drop(arch_boot_params_guard);

kinfo!(
Expand Down
3 changes: 2 additions & 1 deletion kernel/src/arch/riscv64/interrupt/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ unsafe extern "C" fn _save_context() -> ! {
off_cause = const offset_of!(TrapFrame, cause),
off_tp = const offset_of!(TrapFrame, tp),
off_epc = const offset_of!(TrapFrame, epc),
sr_sum_and_fsvs = const (SR_FS_VS | SR_SUM),
sr_sum_and_fsvs = const (0), // 暂时在内核中不禁用FPU和Vector,以及不禁用用户内存访问
// sr_sum_and_fsvs = const (SR_FS_VS | SR_SUM),
csr_status = const CSR_SSTATUS,
csr_epc = const CSR_SEPC,
csr_tval = const CSR_STVAL,
Expand Down
25 changes: 17 additions & 8 deletions kernel/src/arch/riscv64/interrupt/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ fn riscv64_do_interrupt(trap_frame: &mut TrapFrame) {

/// 处理异常
fn riscv64_do_exception(trap_frame: &mut TrapFrame) {
kdebug!(
"riscv64_do_exception: from_user: {}",
trap_frame.is_from_user()
);
let code = trap_frame.cause.code();

if code < EXCEPTION_HANDLERS.len() {
Expand Down Expand Up @@ -153,8 +149,16 @@ fn do_trap_user_env_call(trap_frame: &mut TrapFrame) -> Result<(), SystemError>
// 9-11 reserved

/// 处理指令页错误异常 #12
fn do_trap_insn_page_fault(_trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
kerror!("riscv64_do_irq: do_insn_page_fault");
fn do_trap_insn_page_fault(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
let vaddr = trap_frame.badaddr;
let cause = trap_frame.cause;
let epc = trap_frame.epc;
kerror!(
"riscv64_do_irq: do_insn_page_fault vaddr: {:#x}, cause: {:?} epc: {:#x}",
vaddr,
cause,
epc
);
loop {
spin_loop();
}
Expand All @@ -179,8 +183,13 @@ fn do_trap_load_page_fault(trap_frame: &mut TrapFrame) -> Result<(), SystemError
// 14 reserved

/// 处理页存储错误异常 #15
fn do_trap_store_page_fault(_trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
kerror!("riscv64_do_irq: do_trap_store_page_fault");
fn do_trap_store_page_fault(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
kerror!(
"riscv64_do_irq: do_trap_store_page_fault: epc: {:#x}, vaddr={:#x}, cause={:?}",
trap_frame.epc,
trap_frame.badaddr,
trap_frame.cause
);
loop {
spin_loop();
}
Expand Down
6 changes: 4 additions & 2 deletions kernel/src/arch/riscv64/mm/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,16 @@ pub(super) unsafe fn riscv_mm_init() -> Result<(), SystemError> {
mem_block_manager()
.reserve_block(KERNEL_BEGIN_PA, KERNEL_END_PA - KERNEL_BEGIN_PA)
.expect("Failed to reserve kernel memory");
// 开启S-mode User Memory Access,允许内核访问用户空间
riscv::register::sstatus::set_sum();

let mut bump_allocator = BumpAllocator::<RiscV64MMArch>::new(0);
let _old_page_table = MMArch::table(PageTableKind::Kernel);
let new_page_table: PhysAddr;

// 使用bump分配器,把所有的内存页都映射到页表
{
kdebug!("to create new page table");
// kdebug!("to create new page table");
// 用bump allocator创建新的页表
let mut mapper: crate::mm::page::PageMapper<MMArch, &mut BumpAllocator<MMArch>> =
crate::mm::page::PageMapper::<MMArch, _>::create(
Expand All @@ -85,7 +87,7 @@ pub(super) unsafe fn riscv_mm_init() -> Result<(), SystemError> {
)
.expect("Failed to create page mapper");
new_page_table = mapper.table().phys();
kdebug!("PageMapper created");
// kdebug!("PageMapper created");

// 取消最开始时候,在head.S中指定的映射(暂时不刷新TLB)
{
Expand Down
5 changes: 4 additions & 1 deletion kernel/src/arch/riscv64/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ impl MemoryManagementArch for RiscV64MMArch {

const ENTRY_FLAG_PRESENT: usize = 1 << 0;

const ENTRY_FLAG_READONLY: usize = 0;
const ENTRY_FLAG_READONLY: usize = (1 << 1);

const ENTRY_FLAG_WRITEABLE: usize = (1 << 2);

const ENTRY_FLAG_READWRITE: usize = (1 << 2) | (1 << 1);

Expand Down Expand Up @@ -176,6 +178,7 @@ impl MemoryManagementArch for RiscV64MMArch {
let ppn = PhysPageFrame::new(table).ppn();
riscv::asm::sfence_vma_all();
satp::set(satp::Mode::Sv39, 0, ppn);
riscv::asm::sfence_vma_all();
}

fn virt_is_valid(virt: VirtAddr) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/arch/riscv64/process/idle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl ProcessManager {
spin_loop();
}

kdebug!("idle loop");
// kdebug!("idle loop");
}
}
}
1 change: 1 addition & 0 deletions kernel/src/arch/riscv64/process/kthread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ impl KernelThreadMechanism {
// 使能中断
frame.status.update_sie(true);
frame.status.update_spp(SPP::Supervisor);
frame.status.update_sum(true);

frame.ra = kernel_thread_bootstrap_stage1 as usize;

Expand Down
94 changes: 78 additions & 16 deletions kernel/src/arch/riscv64/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
PROCESS_SWITCH_RESULT,
},
smp::cpu::ProcessorId,
syscall::Syscall,
};

use super::{
Expand All @@ -53,7 +54,64 @@ static BSP_IDLE_STACK_SPACE: InitProcUnion = InitProcUnion {
};

pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<String>) -> ! {
unimplemented!("RiscV64 arch_switch_to_user")
// 以下代码不能发生中断
CurrentIrqArch::interrupt_disable();

let current_pcb = ProcessManager::current_pcb();
let trap_frame_vaddr = VirtAddr::new(
current_pcb.kernel_stack().stack_max_address().data() - core::mem::size_of::<TrapFrame>(),
);
let new_pc = VirtAddr::new(ret_from_exception as usize);

let mut arch_guard = current_pcb.arch_info_irqsave();
arch_guard.ksp = trap_frame_vaddr.data();

arch_guard.ra = new_pc.data();
drop(arch_guard);

// 删除kthread的标志
current_pcb.flags().remove(ProcessFlags::KTHREAD);
current_pcb.worker_private().take();

*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;

let mut trap_frame = TrapFrame::new();

compiler_fence(Ordering::SeqCst);
Syscall::do_execve(path, argv, envp, &mut trap_frame).unwrap_or_else(|e| {
panic!(
"arch_switch_to_user(): pid: {pid:?}, Failed to execve: , error: {e:?}",
pid = current_pcb.pid(),
e = e
);
});
compiler_fence(Ordering::SeqCst);

// 重要!在这里之后,一定要保证上面的引用计数变量、动态申请的变量、锁的守卫都被drop了,否则可能导致内存安全问题!

drop(current_pcb);

*(trap_frame_vaddr.data() as *mut TrapFrame) = trap_frame;

compiler_fence(Ordering::SeqCst);
ready_to_switch_to_user(trap_frame_vaddr.data(), new_pc.data());
}

#[naked]
unsafe extern "C" fn ready_to_switch_to_user(trap_frame: usize, new_pc: usize) -> ! {
asm!(
concat!(
"
// 设置trap frame
mv sp, a0
// 设置返回地址
jr a1
"
),
options(noreturn)
);
}

impl ProcessManager {
Expand Down Expand Up @@ -98,6 +156,7 @@ impl ProcessManager {
let current_arch_guard = current_pcb.arch_info_irqsave();
// 拷贝浮点寄存器的状态
new_arch_guard.fp_state = current_arch_guard.fp_state;
new_arch_guard.sstatus = current_arch_guard.sstatus;

drop(current_arch_guard);

Expand Down Expand Up @@ -128,11 +187,11 @@ impl ProcessManager {
/// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/include/asm/switch_to.h#76
pub unsafe fn switch_process(prev: Arc<ProcessControlBlock>, next: Arc<ProcessControlBlock>) {
assert!(!CurrentIrqArch::is_irq_enabled());
kdebug!(
"riscv switch process: prev: {:?}, next: {:?}",
prev.pid(),
next.pid()
);
// kdebug!(
// "riscv switch process: prev: {:?}, next: {:?}",
// prev.pid(),
// next.pid()
// );
Self::switch_process_fpu(&prev, &next);
Self::switch_local_context(&prev, &next);

Expand All @@ -144,6 +203,8 @@ impl ProcessManager {
drop(next_addr_space);
compiler_fence(Ordering::SeqCst);

// kdebug!("current sum={}, prev sum={}, next_sum={}", riscv::register::sstatus::read().sum(), prev.arch_info_irqsave().sstatus.sum(), next.arch_info_irqsave().sstatus.sum());

// 获取arch info的锁,并强制泄露其守卫(切换上下文后,在switch_finish_hook中会释放锁)
let next_arch = SpinLockGuard::leak(next.arch_info_irqsave()) as *mut ArchPCBInfo;
let prev_arch = SpinLockGuard::leak(prev.arch_info_irqsave()) as *mut ArchPCBInfo;
Expand All @@ -153,7 +214,7 @@ impl ProcessManager {
ProcessManager::current_pcb().preempt_enable();
PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().prev_pcb = Some(prev);
PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().next_pcb = Some(next);
kdebug!("riscv switch process: before to inner");
// kdebug!("riscv switch process: before to inner");
compiler_fence(Ordering::SeqCst);
// 正式切换上下文
switch_to_inner(prev_arch, next_arch);
Expand Down Expand Up @@ -206,8 +267,8 @@ unsafe extern "C" fn switch_to_inner(prev: *mut ArchPCBInfo, next: *mut ArchPCBI
addi sp , sp, -8
sd a1, 0(sp)
csrr a0, sstatus
sd a0, {off_sstatus}(a1)
csrr a1, sstatus
sd a1, {off_sstatus}(a0)
ld a1, 0(sp)
addi sp, sp, 8
Expand Down Expand Up @@ -271,13 +332,12 @@ unsafe extern "C" fn switch_to_inner(prev: *mut ArchPCBInfo, next: *mut ArchPCBI
/// 在切换上下文完成后的钩子函数(必须在这里加一个跳转函数,否则会出现relocation truncated to fit: R_RISCV_JAL错误)
unsafe extern "C" fn before_switch_finish_hook() {
let pcb = ProcessManager::current_pcb();
kdebug!(
"before_switch_finish_hook, pid: {:?}, name: {:?}",
pcb.pid(),
pcb.basic().name()
);
// kdebug!(
// "before_switch_finish_hook, pid: {:?}, name: {:?}",
// pcb.pid(),
// pcb.basic().name()
// );
switch_finish_hook();
kdebug!("after switch_finish_hook");
}

impl ProcessControlBlock {
Expand Down Expand Up @@ -344,6 +404,8 @@ impl ArchPCBInfo {
///
/// 返回一个新的ArchPCBInfo
pub fn new(kstack: &KernelStack) -> Self {
let mut sstatus = Sstatus::from(0);
sstatus.update_sum(true);
Self {
ra: 0,
ksp: kstack.stack_max_address().data(),
Expand All @@ -359,7 +421,7 @@ impl ArchPCBInfo {
s9: 0,
s10: 0,
s11: 0,
sstatus: Sstatus::from(0),
sstatus,
fp_state: FpDExtState::new(),
local_context: LocalContext::new(ProcessorId::new(0)),
}
Expand Down
Loading

0 comments on commit abdf4ce

Please sign in to comment.