Skip to content

Commit 0d21573

Browse files
committed
feat(arch): support mmap and process fork for riscv64
1 parent 14a5bfd commit 0d21573

16 files changed

Lines changed: 271 additions & 34 deletions

File tree

api/ruxos_posix_api/src/imp/execve/mod.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod load_elf;
33
mod stack;
44

55
use alloc::vec;
6-
use core::ffi::c_char;
6+
use core::{ffi::c_char, ptr::null};
77
use ruxtask::current;
88

99
use crate::{
@@ -107,11 +107,13 @@ pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
107107

108108
let mut argv = argv as *const usize;
109109
unsafe {
110-
while *argv != 0 {
111-
arg_vec.push(*argv);
112-
argv = argv.add(1);
110+
if !argv.is_null() {
111+
while *argv != 0 {
112+
arg_vec.push(*argv);
113+
argv = argv.add(1);
114+
}
115+
arg_vec.push(0);
113116
}
114-
arg_vec.push(0);
115117
}
116118

117119
// push
@@ -167,6 +169,17 @@ fn set_sp_and_jmp(sp: usize, entry: usize) -> ! {
167169
in(reg)entry,
168170
);
169171
}
172+
#[cfg(target_arch = "riscv64")]
173+
unsafe {
174+
core::arch::asm!(
175+
"
176+
mv sp, {0}
177+
jalr {1}
178+
",
179+
in(reg) sp,
180+
in(reg) entry,
181+
);
182+
}
170183
unreachable!("sys_execve: unknown arch, sp 0x{sp:x}, entry 0x{entry:x}");
171184
}
172185

api/ruxos_posix_api/src/imp/mmap/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
cfg_if::cfg_if! {
1111
// for X86_64 with SMP, it must flush TLB via IPI
12-
if #[cfg( all(feature = "paging", any(target_arch = "aarch64", any( all(target_arch = "x86_64", feature = "irq", feature = "smp"), all(target_arch = "x86_64", not(feature = "smp")) ) ) ))] {
12+
if #[cfg( all(feature = "paging", any(target_arch = "aarch64",target_arch="riscv64",any( all(target_arch = "x86_64", feature = "irq", feature = "smp"), all(target_arch = "x86_64", not(feature = "smp")) ) ) ))] {
1313
#[macro_use]
1414
mod utils;
1515
mod api;

api/ruxos_posix_api/src/imp/pthread/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,24 @@ pub unsafe fn sys_clone(
374374
ruxtask::put_task(task_inner);
375375

376376
return Ok(tid);
377+
} else if (flags as u32 & ctypes::SIGCHLD) != 0 {
378+
let pid = if let Some(task_ref) = ruxtask::fork_task() {
379+
task_ref.id().as_u64()
380+
} else {
381+
let children_ref = ruxtask::current();
382+
let tid = children_ref.id().as_u64();
383+
let thread = Pthread {
384+
inner: children_ref.clone_as_taskref(),
385+
retval: Arc::new(Packet {
386+
result: UnsafeCell::new(core::ptr::null_mut()),
387+
}),
388+
};
389+
let ptr = Box::into_raw(Box::new(thread)) as *mut c_void;
390+
TID_TO_PTHREAD.write().insert(tid, ForceSendSync(ptr));
391+
0
392+
};
393+
debug!("will sys_clone <= pid: {}", pid);
394+
return Ok(pid);
377395
} else {
378396
debug!("ONLY support CLONE_THREAD and SIGCHLD");
379397
return Err(LinuxError::EINVAL);

modules/ruxhal/src/arch/riscv/context.rs

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
*/
99

1010
use core::arch::naked_asm;
11+
use memory_addr::PhysAddr;
1112
use memory_addr::VirtAddr;
1213

14+
use super::reg_satp::RegSatp;
15+
1316
include_asm_marcos!();
1417

1518
/// General registers of RISC-V.
@@ -60,6 +63,7 @@ pub struct TrapFrame {
6063
pub sepc: usize,
6164
/// Supervisor Status Register.
6265
pub sstatus: usize,
66+
pub sscratch: usize,
6367
}
6468

6569
/// Saved hardware states of a task.
@@ -95,6 +99,7 @@ pub struct TaskContext {
9599
pub s11: usize,
96100

97101
pub tp: usize,
102+
pub gp: usize,
98103
// TODO: FP states
99104
}
100105

@@ -116,21 +121,96 @@ impl TaskContext {
116121
///
117122
/// It first saves the current task's context from CPU to this place, and then
118123
/// restores the next task's context from `next_ctx` to CPU.
119-
pub fn switch_to(&mut self, next_ctx: &Self) {
124+
pub fn switch_to(&mut self, next_ctx: &Self, page_table_addr: PhysAddr) {
120125
#[cfg(feature = "tls")]
121126
{
122127
self.tp = super::read_thread_pointer();
123128
unsafe { super::write_thread_pointer(next_ctx.tp) };
124129
}
130+
131+
let satp = RegSatp::gen_satp(riscv::register::satp::Mode::Sv39, 0, page_table_addr.into());
125132
unsafe {
126133
// TODO: switch FP states
127-
context_switch(self, next_ctx)
134+
context_switch(self, next_ctx, satp);
128135
}
129136
}
137+
138+
/// This function copy the content from src to dst,the content size is given by parameter "size"
139+
/// It's only supposed to use this function for processes stack's copying
140+
/// Not only the content of the src process's stack would be copied into dst's
141+
/// It would also save the current context of the process to src's stack
142+
///
143+
/// # Argument
144+
/// - src: The raw pointer of the src process stack
145+
/// - dst: The raw pointer of the dst process stack
146+
/// - size: The size of the stack
147+
///
148+
/// # Safety
149+
/// This function assumes that the parameter "size" indicate exactly the size of both stacks.
150+
/// The caller must ensure this to make safe function call.
151+
pub unsafe fn save_current_content(&mut self, src: *const u8, dst: *mut u8, size: usize) {
152+
unsafe {
153+
save_stack(src, dst, size);
154+
save_current_context(self);
155+
}
156+
}
157+
}
158+
159+
#[unsafe(naked)]
160+
#[allow(named_asm_labels)]
161+
unsafe extern "C" fn save_current_context(_current_task: &mut TaskContext) {
162+
naked_asm!(
163+
"
164+
sd ra,0(a0)
165+
sd sp,8(a0)
166+
sd s0,16(a0)
167+
sd s1,24(a0)
168+
sd s2,32(a0)
169+
sd s3,40(a0)
170+
sd s4,48(a0)
171+
sd s5,56(a0)
172+
sd s6,64(a0)
173+
sd s7,72(a0)
174+
sd s8,80(a0)
175+
sd s9,88(a0)
176+
sd s10,96(a0)
177+
sd s11,104(a0)
178+
sd tp,112(a0)
179+
ret
180+
"
181+
)
182+
}
183+
184+
#[unsafe(naked)]
185+
#[no_mangle]
186+
#[allow(named_asm_labels)]
187+
// TODO: consider using SIMD instructions to copy the stack in parallel.
188+
unsafe extern "C" fn save_stack(src: *const u8, dst: *mut u8, size: usize) {
189+
// a0:src ; a1:dst ; a2:size
190+
naked_asm!(
191+
"
192+
xor a4,a4,a4
193+
add a4,a4,a2
194+
start_copy:
195+
ld a5,0(a0)
196+
sd a5,0(a1)
197+
addi a0,a0,8
198+
addi a1,a1,8
199+
addi a4,a4,-8
200+
bnez a4,start_copy
201+
ret
202+
203+
"
204+
)
130205
}
131206

132207
#[unsafe(naked)]
133-
unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task: &TaskContext) {
208+
#[allow(named_asm_labels)]
209+
unsafe extern "C" fn context_switch(
210+
_current_task: &mut TaskContext,
211+
_next_task: &TaskContext,
212+
_page_table_addr: usize,
213+
) {
134214
naked_asm!(
135215
"
136216
// save old context (callee-saved registers)
@@ -149,6 +229,12 @@ unsafe extern "C" fn context_switch(_current_task: &mut TaskContext, _next_task:
149229
sd s10, 96(a0)
150230
sd s11, 104(a0)
151231
232+
csrr a3,satp
233+
csrw satp,a2
234+
xor a3,a3,a2
235+
beqz a3,set_satp_done
236+
sfence.vma
237+
set_satp_done:
152238
// restore new context
153239
ld s11, 104(a1)
154240
ld s10, 96(a1)

modules/ruxhal/src/arch/riscv/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
mod macros;
1212

1313
mod context;
14+
mod reg_satp;
1415
mod trap;
15-
1616
use memory_addr::{PhysAddr, VirtAddr};
1717
use riscv::asm;
1818
use riscv::register::{satp, sstatus, stvec};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use riscv::register::satp;
2+
3+
type PhysAddr = usize;
4+
5+
#[allow(clippy::upper_case_acronyms)]
6+
pub struct PPN(usize);
7+
8+
impl From<PhysAddr> for PPN {
9+
fn from(value: PhysAddr) -> Self {
10+
let num = value;
11+
let page_frame_num = num >> 12;
12+
Self(page_frame_num)
13+
}
14+
}
15+
16+
impl From<PPN> for usize {
17+
fn from(value: PPN) -> Self {
18+
value.0
19+
}
20+
}
21+
pub struct AddressSpaceID(usize);
22+
23+
impl From<u16> for AddressSpaceID {
24+
fn from(value: u16) -> Self {
25+
let value = usize::from(value);
26+
AddressSpaceID(value << 44)
27+
}
28+
}
29+
30+
impl From<AddressSpaceID> for usize {
31+
fn from(value: AddressSpaceID) -> Self {
32+
value.0
33+
}
34+
}
35+
36+
pub struct RegSatp;
37+
38+
impl RegSatp {
39+
pub fn gen_satp(mode: satp::Mode, asid: u16, page_table_addr: PhysAddr) -> usize {
40+
let mode = (mode as usize) << 60;
41+
let asid: AddressSpaceID = asid.into();
42+
let physical_page_num: PPN = page_table_addr.into();
43+
mode | usize::from(asid) | usize::from(physical_page_num)
44+
}
45+
}

modules/ruxhal/src/arch/riscv/trap.S

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,35 @@
11
.macro SAVE_REGS, from_user
22
addi sp, sp, -{trapframe_size}
33
PUSH_GENERAL_REGS
4-
4+
addi t2, sp, {trapframe_size}
55
csrr t0, sepc
66
csrr t1, sstatus
7-
csrrw t2, sscratch, zero // save sscratch (sp) and zero it
87
STR t0, sp, 31 // tf.sepc
98
STR t1, sp, 32 // tf.sstatus
9+
STR gp, sp, 2
1010
STR t2, sp, 1 // tf.regs.sp
11-
11+
csrr gp, sscratch
1212
.if \from_user == 1
1313
LDR t0, sp, 3 // load supervisor tp
14-
STR gp, sp, 2 // save user gp and tp
1514
STR tp, sp, 3
1615
mv tp, t0
1716
.endif
1817
.endm
1918

2019
.macro RESTORE_REGS, from_user
20+
// LDR gp, sp, 2
2121
.if \from_user == 1
22-
LDR gp, sp, 2 // load user gp and tp
2322
LDR t0, sp, 3
2423
STR tp, sp, 3 // save supervisor tp
2524
mv tp, t0
2625
addi t0, sp, {trapframe_size} // put supervisor sp to scratch
27-
csrw sscratch, t0
2826
.endif
29-
27+
LDR gp, sp, 2
3028
LDR t0, sp, 31
3129
LDR t1, sp, 32
3230
csrw sepc, t0
3331
csrw sstatus, t1
34-
32+
//csrw sscratch, t2
3533
POP_GENERAL_REGS
3634
LDR sp, sp, 1 // load sp from tf.regs.sp
3735
.endm
@@ -42,10 +40,9 @@
4240
trap_vector_base:
4341
// sscratch == 0: trap from S mode
4442
// sscratch != 0: trap from U mode
45-
csrrw sp, sscratch, sp // switch sscratch and sp
46-
bnez sp, .Ltrap_entry_u
47-
48-
csrr sp, sscratch // put supervisor sp back
43+
//csrrw sp, sscratch, sp // switch sscratch and sp
44+
//bnez sp, .Ltrap_entry_u
45+
//csrr sp, sscratch // put supervisor sp back
4946
j .Ltrap_entry_s
5047

5148
.Ltrap_entry_s:

modules/ruxhal/src/arch/riscv/trap.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use riscv::register::scause::{self, Exception as E, Trap};
1111

12-
use super::TrapFrame;
12+
use super::{disable_irqs, enable_irqs, TrapFrame};
1313

1414
include_asm_marcos!();
1515

@@ -31,6 +31,8 @@ fn riscv_trap_handler(tf: &mut TrapFrame, _from_user: bool) {
3131
Trap::Interrupt(_) => crate::trap::handle_irq_extern(scause.bits()),
3232
#[cfg(feature = "musl")]
3333
Trap::Exception(E::UserEnvCall) => {
34+
#[cfg(feature = "irq")]
35+
enable_irqs();
3436
let ret = crate::trap::handle_syscall(
3537
tf.regs.a7,
3638
[
@@ -43,6 +45,23 @@ fn riscv_trap_handler(tf: &mut TrapFrame, _from_user: bool) {
4345
],
4446
);
4547
tf.regs.a0 = ret as _;
48+
#[cfg(feature = "irq")]
49+
disable_irqs();
50+
}
51+
#[cfg(feature = "paging")]
52+
Trap::Exception(E::LoadPageFault) => {
53+
let vaddr = riscv::register::stval::read();
54+
crate::trap::handle_page_fault(vaddr, crate::trap::PageFaultCause::READ);
55+
}
56+
#[cfg(feature = "paging")]
57+
Trap::Exception(E::StorePageFault) => {
58+
let vaddr = riscv::register::stval::read();
59+
crate::trap::handle_page_fault(vaddr, crate::trap::PageFaultCause::WRITE);
60+
}
61+
#[cfg(feature = "paging")]
62+
Trap::Exception(E::InstructionPageFault) => {
63+
let vaddr = riscv::register::stval::read();
64+
crate::trap::handle_page_fault(vaddr, crate::trap::PageFaultCause::INSTRUCTION);
4665
}
4766
_ => {
4867
panic!(

0 commit comments

Comments
 (0)