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