1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#![no_std]
#![no_main]
#![feature(panic_info_message)]
#![feature(alloc_error_handler)]
#![feature(naked_functions)]
#![feature(fn_align)]

use crate::drivers::{GPU_DEVICE, KEYBOARD_DEVICE, MOUSE_DEVICE};

extern crate alloc;

#[macro_use]
extern crate bitflags;

#[path = "boards/qemu.rs"]
mod board;
use board::*;
#[macro_use]
mod console;
mod config;
mod drivers;
mod fs;
mod gui;
mod lang_items;
mod mm;
mod sbi;
mod sync;
mod syscall;
mod task;
mod timer;
mod trap;

use riscv::register::*;
// mod riscvreg;
// use riscvreg::{
//     mstatus, mepc, satp, medeleg, mideleg, sie, mhartid, tp, clint, 
//     mscratch, mtvec, mie, sstatus
// };
// use riscvregs::registers::*;
// use riscvregs::registers::pmpcfg0::*;
//use syscall::create_desktop; //for test

core::arch::global_asm!(include_str!("entry.asm"));

fn clear_bss() {
    extern "C" {
        fn sbss();
        fn ebss();
    }
    unsafe {
        core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize)
            .fill(0);
    }
}

use lazy_static::*;
use sync::UPIntrFreeCell;

lazy_static! {
    pub static ref DEV_NON_BLOCKING_ACCESS: UPIntrFreeCell<bool> =
        unsafe { UPIntrFreeCell::new(false) };
}


#[repr(C, align(16))]
struct Stack([u8; 4096 * 4 * 1]);

#[no_mangle]
static mut STACK0: Stack = Stack([0; 4096 * 4 * 1]);

#[inline]
pub unsafe fn medeleg_write(medeleg: usize){
    core::arch::asm!("csrw medeleg, {}",in(reg)medeleg);
}

pub unsafe fn mideleg_write(mideleg: usize) {
    core::arch::asm!("csrw mideleg, {}", in(reg)mideleg);
}

pub enum SIE {
    SEIE = 1 << 9, // external
    STIE = 1 << 5, // timer
    SSIE = 1 << 1, // software
}

#[inline]
pub unsafe fn sie_read() -> usize {
    let ret:usize;
    core::arch::asm!("csrr {}, sie", out(reg)ret);
    ret
}

#[inline]
pub unsafe fn sie_write(x:usize) {
    core::arch::asm!("csrw sie, {}", in(reg)x);
}

/// enable all software interrupts
/// still need to set SIE bit in sstatus
pub unsafe fn intr_on() {
    let mut sie = sie_read();
    sie |= SIE::SSIE as usize | SIE::STIE as usize | SIE::SEIE as usize;
    sie_write(sie);
}

#[no_mangle]
pub unsafe fn rust_start() -> ! {
    // set MPP mode to Supervisor, for mret
    mstatus::set_mpp(mstatus::MPP::Supervisor);

    // set MEPC to main, for mret
    mepc::write(rust_main as usize);

    // disable paging for now.
    satp::write(0);

    // delegate all interrupts and exceptions to supervisor mode.
    medeleg_write(0xffff);
    mideleg_write(0xffff);
    intr_on();

    // configure Physical Memory Protection to give supervisor mode
    // access to all of physical memory.
    pmpaddr0::write(0x3fffffffffffff);
    pmpcfg0::write(0xf);
    //pmpcfg0::set_pmp(0, Range::TOR, Permission::RWX, false); // 0 < addr < pmpaddr0

    // ask for clock interrupts.
    timer_init();

    // keep each CPU's hartid in its tp register, for cpuid().
    // let id = mhartid::read();
    // core::arch::asm!("mv tp, {0}", in(reg) id);

    // switch to supervisor mode and jump to main().
    core::arch::asm!("mret");

    extern "C" {
        fn rust_main() -> !;
    }
    core::hint::unreachable_unchecked();
}

use core::convert::Into;
use core::ptr;

// a scratch area per CPU for machine-mode timer interrupts.
static mut TIMER_SCRATCH: [u64; 5] = [0; 5];

#[inline]
unsafe fn read_mtime() -> u64 {
    ptr::read_volatile(Into::<usize>::into(CLINT_MTIME) as *const u64)
}

unsafe fn write_mtimecmp(value: u64) {
    let offset = Into::<usize>::into(CLINT_MTIMECMP);
    ptr::write_volatile(offset as *mut u64, value);
}

pub unsafe fn add_mtimecmp(interval:u64){
    let value = read_mtime();
    write_mtimecmp(value+interval);
}

pub fn count_mtiecmp() -> usize{
    let ret:usize;
    ret = Into::<usize>::into(CLINT) + 0x4000;
    ret
}

#[inline]
pub unsafe fn mtvec_write(x:usize){
    core::arch::asm!("csrw mtvec, {}",in(reg)x);
}

use bit_field::BitField;

#[inline]
unsafe fn mstatus_read() -> usize {
    let ret:usize;
    core::arch::asm!("csrr {}, mstatus",out(reg)ret);
    ret
}

#[inline]
unsafe fn mstatus_write(x: usize) {
    core::arch::asm!("csrw mstatus, {}",in(reg)x);
}

// enable machine-mode interrupts.
pub unsafe fn mstatus_enable_interrupt(){
    let mut mstatus = mstatus_read();
    mstatus.set_bit(3, true);
    mstatus_write(mstatus);
}


pub enum MIE {
    MEIE = 1 << 11, // external
    MTIE = 1 << 7,  // timer
    MSIE = 1 << 3  // software
}

#[inline]
pub unsafe fn mie_read() -> usize {
    let ret:usize;
    core::arch::asm!("csrr {}, mie", out(reg)ret);
    ret
}

#[inline]
pub unsafe fn mie_write(x:usize){
    core::arch::asm!("csrw mie, {}",in(reg)x);
}

unsafe fn timer_init() {
    clear_bss();
    // each CPU has a separate source of timer interrupts
    //let id = mhartid::read();

    // ask the CLINT for a timer interrupts
    let interval = 1000000u64; // cycles; about 1/10th second in qemu.
    add_mtimecmp(interval);
    // let mtimecmp = board::clint_mtimecmp(0) as *mut u64;
    // let mtime = board::CLINT_MTIME as *const u64;
    // mtimecmp.write_volatile(mtime.read_volatile() + interval);

    // prepare information in scratch[] for timervec.
    // scratch[0..2] : space for timervec to save registers.
    // scratch[3] : address of CLINT MTIMECMP register.
    // scratch[4] : desired interval (in cycles) between timer interrupts.
    let scratch = &mut TIMER_SCRATCH;
    scratch[3] = count_mtiecmp() as u64;
    scratch[4] = interval;
    mscratch::write(scratch.as_mut_ptr() as usize);

    // set the machine-mode trap handler
    mtvec_write(timervec as usize);
    //mtvec::write(board::timervec as usize, mtvec::TrapMode::Direct);

    // enable machine-mode interrupts.
    mstatus_enable_interrupt();
    //mstatus::set_mie();

    // enable machine-mode timer interrupts.
    mie_write(mie_read() | MIE::MTIE as usize);
    //mie::set_mtimer();
}

use crate::drivers::chardev::CharDevice;
use crate::drivers::chardev::UART;
#[no_mangle]
pub fn rust_main() -> ! {

    //clear_bss();
    mm::init();
    UART.init();
    println!("KERN: begin");
    //loop{};
    println!("KERN: init gpu");
    let _gpu = GPU_DEVICE.clone();
    println!("KERN: init keyboard");
    let _keyboard = KEYBOARD_DEVICE.clone();
    println!("KERN: init mouse");
    let _mouse = MOUSE_DEVICE.clone();
    println!("KERN: init trap");
    trap::init();
    //trap::enable_timer_interrupt();
    //timer::set_next_trigger();
    board::device_init();
    fs::list_apps();
    //gui::init_paint();
    task::add_initproc();
    *DEV_NON_BLOCKING_ACCESS.exclusive_access() = true;
    task::run_tasks();
    panic!("Unreachable in rust_main!");
}