kernel/arch/riscv64/
mod.rs

1use core::arch::asm;
2use core::mem::transmute;
3use instruction::sbi::sbi_system_reset;
4use trap::kernel::arch_kernel_trap_handler;
5use trap::kernel::_kernel_trap_entry;
6use trap::user::_user_trap_entry;
7use trap::user::arch_user_trap_handler;
8use vcpu::Mode;
9
10use crate::arch::instruction::Instruction;
11use crate::arch::vm::get_root_pagetable;
12use crate::early_println;
13use crate::environment::NUM_OF_CPUS;
14use crate::environment::STACK_SIZE;
15use crate::mem::KERNEL_STACK;
16use crate::task::Task;
17
18pub mod boot;
19pub mod instruction;
20pub mod interrupt;
21pub mod kernel;
22pub mod trap;
23pub mod earlycon;
24pub mod vcpu;
25pub mod timer;
26pub mod vm;
27pub mod registers;
28
29pub use earlycon::*;
30pub use registers::Registers;
31
32pub type Arch = Riscv64;
33pub type Trapframe = Riscv64;
34
35#[unsafe(link_section = ".trampoline.data")]
36static mut TRAPFRAME: [Riscv64; NUM_OF_CPUS] = [const { Riscv64::new(0) }; NUM_OF_CPUS];
37
38#[repr(align(4))]
39#[derive(Debug, Clone)]
40pub struct Riscv64 {
41    pub regs: Registers,
42    pub epc: u64,
43    pub hartid: u64,
44    satp: u64,
45    kernel_stack: u64,
46    kernel_trap: u64,
47}
48
49pub fn init_arch(cpu_id: usize) {
50    early_println!("[riscv64] Hart {}: Initializing core....", cpu_id);
51    // Get raw Riscv64 struct
52    let riscv: &mut Riscv64 = unsafe { transmute(&TRAPFRAME[cpu_id] as *const _ as usize ) };
53    trap_init(riscv);
54}
55
56impl Riscv64 {
57    pub const fn new(cpu_id: usize) -> Self {
58        Riscv64 { hartid: cpu_id as u64, epc: 0, regs: Registers::new(), kernel_stack: 0, kernel_trap: 0, satp: 0 }
59    }
60
61    pub fn get_cpuid(&self) -> usize {
62        self.hartid as usize
63    }
64
65    pub fn get_trapframe_paddr(&self) -> usize {
66        /* Get pointer of TRAP_FRAME[hartid] */
67        let addr = unsafe { &raw mut TRAPFRAME[self.hartid as usize] } as *const _ as usize;
68        addr
69    }
70
71    pub fn get_trapframe(&mut self) -> &mut Trapframe {
72        self
73    }
74}
75
76impl Trapframe {
77    pub fn set_trap_handler(&mut self, addr: usize) {
78        self.kernel_trap = addr as u64;
79    }
80
81    pub fn set_next_address_space(&mut self, asid: u16) {
82        let root_pagetable = get_root_pagetable(asid).expect("No root page table found for ASID");
83
84        let satp = root_pagetable.get_val_for_satp(asid);
85        self.satp = satp as u64;
86    }
87
88
89    pub fn get_syscall_number(&self) -> usize {
90        self.regs.reg[17] // a7
91    }
92
93    pub fn set_syscall_number(&mut self, syscall_number: usize) {
94        self.regs.reg[17] = syscall_number; // a7
95    }
96
97    pub fn get_return_value(&self) -> usize {
98        self.regs.reg[10] // a0
99    }
100
101    pub fn set_return_value(&mut self, value: usize) {
102        self.regs.reg[10] = value; // a0
103    }
104
105    pub fn get_arg(&self, index: usize) -> usize {
106        self.regs.reg[index + 10] // a0 - a7
107    }
108
109    pub fn set_arg(&mut self, index: usize, value: usize) {
110        self.regs.reg[index + 10] = value; // a0 - a7
111    }
112
113    /// Increment the program counter (epc) to the next instruction
114    /// This is typically used after handling a trap or syscall to continue execution.
115    /// 
116    pub fn increment_pc_next(&mut self, task: &Task) {
117        let instruction = Instruction::fetch(
118            task.vm_manager.translate_vaddr(self.epc as usize).unwrap()
119        );
120        let len = instruction.len();
121        if len == 0 {
122            debug_assert!(len > 0, "Invalid instruction length: {}", len);
123            early_println!("Warning: Invalid instruction length encountered. Defaulting to 4 bytes.");
124            self.epc += 4; // Default to 4 bytes for invalid instruction length
125        } else {
126            self.epc += len as u64;
127        }
128    }
129}
130
131pub fn get_user_trapvector_paddr() -> usize {
132    _user_trap_entry as usize
133}
134
135pub fn get_kernel_trapvector_paddr() -> usize {
136    _kernel_trap_entry as usize
137}
138
139pub fn get_kernel_trap_handler() -> usize {
140    arch_kernel_trap_handler as usize
141}
142
143pub fn get_user_trap_handler() -> usize {
144    arch_user_trap_handler as usize
145}
146
147#[allow(static_mut_refs)]
148fn trap_init(riscv: &mut Riscv64) {
149    early_println!("[riscv64] Hart {}: Initializing trap....", riscv.hartid);
150    
151    let trap_stack_top = unsafe { KERNEL_STACK.top() };
152    let stack_size =  STACK_SIZE;
153
154    let trap_stack = trap_stack_top + stack_size * (riscv.hartid + 1) as usize;
155    early_println!("[riscv64] Hart {}: Trap stack top     : {:#x}", riscv.hartid, trap_stack_top);
156    early_println!("[riscv64] Hart {}: Trap stack bottom  : {:#x}", riscv.hartid, trap_stack);
157
158    early_println!("[riscv64] Hart {}: Trap stack size    : {:#x}", riscv.hartid, stack_size);
159
160    // Setup for Scratch space for Riscv64 struct
161    early_println!("[riscv64] Hart {}: Setting up scratch space....", riscv.hartid);
162    riscv.kernel_stack = trap_stack as u64;
163    riscv.kernel_trap = arch_kernel_trap_handler as u64;
164    
165    let scratch_addr = riscv as *const _ as usize;
166    early_println!("[riscv64] Hart {}: Scratch address    : {:#x}", riscv.hartid, scratch_addr);
167    let sie: usize = 0x20;
168    unsafe {
169        asm!("
170        csrw  sie, {0}
171        csrsi sstatus, 0x2
172        csrw  stvec, {1}
173        csrw  sscratch, {2}
174        ",
175        in(reg) sie,
176        in(reg) _kernel_trap_entry as usize,
177        in(reg) scratch_addr,
178        );
179    }
180}
181
182pub fn set_trapvector(addr: usize) {
183    unsafe {
184        asm!("
185        csrw stvec, {0}
186        ",
187        in(reg) addr,
188        );
189    }
190}
191
192pub fn set_trapframe(addr: usize) {
193    unsafe {
194        asm!("
195        csrw sscratch, {0}
196        ",
197        in(reg) addr,
198        );
199    }
200}
201
202pub fn enable_interrupt() {
203    unsafe {
204        asm!("
205        csrsi sstatus, 0x2
206        ");
207    }
208}
209
210pub fn disable_interrupt() {
211    unsafe {
212        asm!("
213        csrci sstatus, 0x2
214        ");
215    }
216}
217
218pub fn get_cpu() -> &'static mut Riscv64 {
219    let scratch: usize;
220
221    unsafe {
222        asm!("
223        csrr {0}, sscratch
224        ",
225        out(reg) scratch,
226        );
227    }
228    unsafe { transmute(scratch) }
229}
230
231pub fn set_next_mode(mode: Mode) {
232    match mode {
233        Mode::User => {
234            unsafe {
235                // sstatus.spp = 0 (U-mode)
236                let mut sstatus: usize;
237                asm!(
238                    "csrr {sstatus}, sstatus",
239                    sstatus = out(reg) sstatus,
240                );
241                sstatus &= !(1 << 8); // Clear SPP bit
242                asm!(
243                    "csrw sstatus, {sstatus}",
244                    sstatus = in(reg) sstatus,
245                );
246            }
247        },
248        Mode::Kernel => {
249            unsafe {
250                // sstatus.spp = 1 (S-mode)
251                let mut sstatus: usize;
252                asm!(
253                    "csrr {sstatus}, sstatus",
254                    sstatus = out(reg) sstatus,
255                );
256                sstatus |= 1 << 8; // Set SPP bit
257                asm!(
258                    "csrw sstatus, {sstatus}",
259                    sstatus = in(reg) sstatus,
260                );
261            }
262        },
263    }
264}
265
266pub fn shutdown() -> ! {
267    sbi_system_reset(0, 0);
268}
269
270pub fn shutdown_with_code(exit_code: u32) -> ! {
271    // Use reset_reason as exit code for test environments
272    sbi_system_reset(0, exit_code);
273}
274
275pub fn reboot() -> ! {
276    sbi_system_reset(1, 0);
277}