mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Add RISC-V base support
This commit is contained in:
parent
839c2a6689
commit
4fa0e6334b
57
Cargo.lock
generated
57
Cargo.lock
generated
@ -187,6 +187,7 @@ dependencies = [
|
|||||||
"ostd",
|
"ostd",
|
||||||
"paste",
|
"paste",
|
||||||
"rand",
|
"rand",
|
||||||
|
"riscv",
|
||||||
"spin 0.9.8",
|
"spin 0.9.8",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"takeable",
|
"takeable",
|
||||||
@ -222,6 +223,7 @@ name = "aster-time"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aster-util",
|
"aster-util",
|
||||||
|
"chrono",
|
||||||
"component",
|
"component",
|
||||||
"log",
|
"log",
|
||||||
"ostd",
|
"ostd",
|
||||||
@ -352,6 +354,15 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "component"
|
name = "component"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -416,6 +427,12 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "critical-section"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@ -531,6 +548,12 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-hal"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -566,6 +589,12 @@ dependencies = [
|
|||||||
"ext-trait",
|
"ext-trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fdt"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -1064,6 +1093,7 @@ dependencies = [
|
|||||||
"buddy_system_allocator",
|
"buddy_system_allocator",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"const-assert",
|
"const-assert",
|
||||||
|
"fdt",
|
||||||
"gimli 0.28.0",
|
"gimli 0.28.0",
|
||||||
"iced-x86",
|
"iced-x86",
|
||||||
"id-alloc",
|
"id-alloc",
|
||||||
@ -1081,7 +1111,9 @@ dependencies = [
|
|||||||
"ostd-pod",
|
"ostd-pod",
|
||||||
"ostd-test",
|
"ostd-test",
|
||||||
"owo-colors 3.5.0",
|
"owo-colors 3.5.0",
|
||||||
|
"riscv",
|
||||||
"rsdp",
|
"rsdp",
|
||||||
|
"sbi-rt",
|
||||||
"spin 0.9.8",
|
"spin 0.9.8",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"tdx-guest",
|
"tdx-guest",
|
||||||
@ -1261,6 +1293,16 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "riscv"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9"
|
||||||
|
dependencies = [
|
||||||
|
"critical-section",
|
||||||
|
"embedded-hal",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rle-decode-fast"
|
name = "rle-decode-fast"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -1282,6 +1324,21 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sbi-rt"
|
||||||
|
version = "0.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fbaa69be1eedc61c426e6d489b2260482e928b465360576900d52d496a58bd0"
|
||||||
|
dependencies = [
|
||||||
|
"sbi-spec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sbi-spec"
|
||||||
|
version = "0.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e36312fb5ddc10d08ecdc65187402baba4ac34585cb9d1b78522ae2358d890"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
23
OSDK.toml
23
OSDK.toml
@ -71,3 +71,26 @@ qemu.args = """\
|
|||||||
-monitor chardev:mux \
|
-monitor chardev:mux \
|
||||||
-serial chardev:mux \
|
-serial chardev:mux \
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
[scheme."riscv"]
|
||||||
|
boot.method = "qemu-direct"
|
||||||
|
build.strip_elf = false
|
||||||
|
|
||||||
|
qemu.path = "./qemu-system-riscv64"
|
||||||
|
qemu.args = """\
|
||||||
|
-cpu rv64,zba=true,zbb=true \
|
||||||
|
-machine virt \
|
||||||
|
-m 8G \
|
||||||
|
--no-reboot \
|
||||||
|
-nographic \
|
||||||
|
-display none \
|
||||||
|
-serial chardev:mux \
|
||||||
|
-monitor chardev:mux \
|
||||||
|
-chardev stdio,id=mux,mux=on,signal=off,logfile=qemu.log \
|
||||||
|
-drive if=none,format=raw,id=x0,file=./test/build/ext2.img \
|
||||||
|
-drive if=none,format=raw,id=x1,file=./test/build/exfat.img \
|
||||||
|
-device virtio-blk-device,drive=x0 \
|
||||||
|
-device virtio-keyboard-device \
|
||||||
|
-device virtio-serial-device \
|
||||||
|
-device virtconsole,chardev=mux \
|
||||||
|
"""
|
||||||
|
@ -58,6 +58,9 @@ getset = "0.1.2"
|
|||||||
takeable = "0.2.2"
|
takeable = "0.2.2"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
|
|
||||||
|
[target.riscv64gc-unknown-none-elf.dependencies]
|
||||||
|
riscv = { version = "0.11.1", features = ["s-mode"] }
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
features = ["spin_no_std"]
|
features = ["spin_no_std"]
|
||||||
|
@ -12,4 +12,7 @@ component = { path = "../../libs/comp-sys/component" }
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
|
|
||||||
|
[target.riscv64gc-unknown-none-elf.dependencies]
|
||||||
|
chrono = { version = "0.4.38", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
46
kernel/comps/time/src/rtc/goldfish.rs
Normal file
46
kernel/comps/time/src/rtc/goldfish.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use ostd::{arch::riscv::timer::GOLDFISH_IO_MEM, mm::VmIoOnce};
|
||||||
|
use chrono::{DateTime, Datelike, Timelike};
|
||||||
|
|
||||||
|
use crate::{SystemTime, rtc::Driver};
|
||||||
|
|
||||||
|
pub struct RtcGoldfish;
|
||||||
|
|
||||||
|
impl Driver for RtcGoldfish {
|
||||||
|
fn try_new() -> Option<RtcGoldfish> {
|
||||||
|
GOLDFISH_IO_MEM.get()?;
|
||||||
|
Some(RtcGoldfish)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_rtc(&self) -> SystemTime {
|
||||||
|
const TIME_LOW: usize = 0;
|
||||||
|
const TIME_HIGH: usize = 4;
|
||||||
|
|
||||||
|
let io_mem = GOLDFISH_IO_MEM.get().unwrap();
|
||||||
|
|
||||||
|
let mut last_time_high = io_mem.read_once(TIME_HIGH).unwrap();
|
||||||
|
let timestamp = loop {
|
||||||
|
let time_low: u32 = io_mem.read_once(TIME_LOW).unwrap();
|
||||||
|
let time_high: u32 = io_mem.read_once(TIME_HIGH).unwrap();
|
||||||
|
if last_time_high == time_high {
|
||||||
|
break ((time_high as u64) << 32) | time_low as u64;
|
||||||
|
}
|
||||||
|
last_time_high = time_high;
|
||||||
|
};
|
||||||
|
|
||||||
|
let time = DateTime::from_timestamp_nanos(timestamp as i64).naive_utc();
|
||||||
|
let (is_ad, year) = time.year_ce();
|
||||||
|
debug_assert!(is_ad, "non-negative timestamp should always be AD");
|
||||||
|
|
||||||
|
SystemTime {
|
||||||
|
year: year as u16,
|
||||||
|
month: time.month() as u8,
|
||||||
|
day: time.day() as u8,
|
||||||
|
hour: time.hour() as u8,
|
||||||
|
minute: time.minute() as u8,
|
||||||
|
second: time.second() as u8,
|
||||||
|
nanos: time.nanosecond() as u64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,4 +39,5 @@ macro_rules! declare_rtc_drivers {
|
|||||||
|
|
||||||
declare_rtc_drivers! {
|
declare_rtc_drivers! {
|
||||||
#[cfg(target_arch = "x86_64")] cmos::RtcCmos,
|
#[cfg(target_arch = "x86_64")] cmos::RtcCmos,
|
||||||
|
#[cfg(target_arch = "riscv64")] goldfish::RtcGoldfish,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
mod riscv;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
mod x86;
|
mod x86;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use riscv::*;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86::*;
|
pub use x86::*;
|
||||||
|
148
kernel/src/arch/riscv/cpu.rs
Normal file
148
kernel/src/arch/riscv/cpu.rs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use ostd::{
|
||||||
|
cpu::{CpuExceptionInfo, RawGeneralRegs, UserContext},
|
||||||
|
Pod,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{cpu::LinuxAbi, thread::exception::PageFaultInfo, vm::perms::VmPerms};
|
||||||
|
|
||||||
|
impl LinuxAbi for UserContext {
|
||||||
|
fn syscall_num(&self) -> usize {
|
||||||
|
self.a7()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn syscall_ret(&self) -> usize {
|
||||||
|
self.a0()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_syscall_ret(&mut self, ret: usize) {
|
||||||
|
self.set_a0(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn syscall_args(&self) -> [usize; 6] {
|
||||||
|
[
|
||||||
|
self.a0(),
|
||||||
|
self.a1(),
|
||||||
|
self.a2(),
|
||||||
|
self.a3(),
|
||||||
|
self.a4(),
|
||||||
|
self.a5(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.set_tp(tls);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tls_pointer(&self) -> usize {
|
||||||
|
self.tp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// General-purpose registers.
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct GpRegs {
|
||||||
|
pub zero: usize,
|
||||||
|
pub ra: usize,
|
||||||
|
pub sp: usize,
|
||||||
|
pub gp: usize,
|
||||||
|
pub tp: usize,
|
||||||
|
pub t0: usize,
|
||||||
|
pub t1: usize,
|
||||||
|
pub t2: usize,
|
||||||
|
pub s0: usize,
|
||||||
|
pub s1: usize,
|
||||||
|
pub a0: usize,
|
||||||
|
pub a1: usize,
|
||||||
|
pub a2: usize,
|
||||||
|
pub a3: usize,
|
||||||
|
pub a4: usize,
|
||||||
|
pub a5: usize,
|
||||||
|
pub a6: usize,
|
||||||
|
pub a7: usize,
|
||||||
|
pub s2: usize,
|
||||||
|
pub s3: usize,
|
||||||
|
pub s4: usize,
|
||||||
|
pub s5: usize,
|
||||||
|
pub s6: usize,
|
||||||
|
pub s7: usize,
|
||||||
|
pub s8: usize,
|
||||||
|
pub s9: usize,
|
||||||
|
pub s10: usize,
|
||||||
|
pub s11: usize,
|
||||||
|
pub t3: usize,
|
||||||
|
pub t4: usize,
|
||||||
|
pub t5: usize,
|
||||||
|
pub t6: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! copy_gp_regs {
|
||||||
|
($src: ident, $dst: ident) => {
|
||||||
|
$dst.zero = $src.zero;
|
||||||
|
$dst.ra = $src.ra;
|
||||||
|
$dst.sp = $src.sp;
|
||||||
|
$dst.gp = $src.gp;
|
||||||
|
$dst.tp = $src.tp;
|
||||||
|
$dst.t0 = $src.t0;
|
||||||
|
$dst.t1 = $src.t1;
|
||||||
|
$dst.t2 = $src.t2;
|
||||||
|
$dst.s0 = $src.s0;
|
||||||
|
$dst.s1 = $src.s1;
|
||||||
|
$dst.a0 = $src.a0;
|
||||||
|
$dst.a1 = $src.a1;
|
||||||
|
$dst.a2 = $src.a2;
|
||||||
|
$dst.a3 = $src.a3;
|
||||||
|
$dst.a4 = $src.a4;
|
||||||
|
$dst.a5 = $src.a5;
|
||||||
|
$dst.a6 = $src.a6;
|
||||||
|
$dst.a7 = $src.a7;
|
||||||
|
$dst.s2 = $src.s2;
|
||||||
|
$dst.s3 = $src.s3;
|
||||||
|
$dst.s4 = $src.s4;
|
||||||
|
$dst.s5 = $src.s5;
|
||||||
|
$dst.s6 = $src.s6;
|
||||||
|
$dst.s7 = $src.s7;
|
||||||
|
$dst.s8 = $src.s8;
|
||||||
|
$dst.s9 = $src.s9;
|
||||||
|
$dst.s10 = $src.s10;
|
||||||
|
$dst.s11 = $src.s11;
|
||||||
|
$dst.t3 = $src.t3;
|
||||||
|
$dst.t4 = $src.t4;
|
||||||
|
$dst.t5 = $src.t5;
|
||||||
|
$dst.t6 = $src.t6;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpRegs {
|
||||||
|
pub fn copy_to_raw(&self, dst: &mut RawGeneralRegs) {
|
||||||
|
copy_gp_regs!(self, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_from_raw(&mut self, src: &RawGeneralRegs) {
|
||||||
|
copy_gp_regs!(src, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&CpuExceptionInfo> for PageFaultInfo {
|
||||||
|
// [`Err`] indicates that the [`CpuExceptionInfo`] is not a page fault,
|
||||||
|
// with no additional error information.
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &CpuExceptionInfo) -> Result<Self, ()> {
|
||||||
|
use riscv::register::scause::Exception;
|
||||||
|
|
||||||
|
let required_perms = match value.cpu_exception() {
|
||||||
|
Exception::InstructionPageFault => VmPerms::EXEC,
|
||||||
|
Exception::LoadPageFault => VmPerms::READ,
|
||||||
|
Exception::StorePageFault => VmPerms::WRITE,
|
||||||
|
_ => return Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(PageFaultInfo {
|
||||||
|
address: value.page_fault_addr,
|
||||||
|
required_perms,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
4
kernel/src/arch/riscv/mod.rs
Normal file
4
kernel/src/arch/riscv/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
pub mod cpu;
|
||||||
|
pub mod signal;
|
19
kernel/src/arch/riscv/signal.rs
Normal file
19
kernel/src/arch/riscv/signal.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use ostd::cpu::{CpuExceptionInfo, UserContext};
|
||||||
|
|
||||||
|
use crate::process::signal::{sig_num::SigNum, signals::fault::FaultSignal, SignalContext};
|
||||||
|
|
||||||
|
impl SignalContext for UserContext {
|
||||||
|
fn set_arguments(&mut self, sig_num: SigNum, siginfo_addr: usize, ucontext_addr: usize) {
|
||||||
|
self.set_a0(sig_num.as_u8() as usize);
|
||||||
|
self.set_a1(siginfo_addr);
|
||||||
|
self.set_a2(ucontext_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&CpuExceptionInfo> for FaultSignal {
|
||||||
|
fn from(trap_info: &CpuExceptionInfo) -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
@ -104,6 +104,7 @@ pub fn init() {
|
|||||||
util::random::init();
|
util::random::init();
|
||||||
driver::init();
|
driver::init();
|
||||||
time::init();
|
time::init();
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
net::init();
|
net::init();
|
||||||
sched::init();
|
sched::init();
|
||||||
fs::rootfs::init(boot::initramfs()).unwrap();
|
fs::rootfs::init(boot::initramfs()).unwrap();
|
||||||
@ -141,6 +142,7 @@ fn init_thread() {
|
|||||||
// Work queue should be initialized before interrupt is enabled,
|
// Work queue should be initialized before interrupt is enabled,
|
||||||
// in case any irq handler uses work queue as bottom half
|
// in case any irq handler uses work queue as bottom half
|
||||||
thread::work_queue::init();
|
thread::work_queue::init();
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
net::lazy_init();
|
net::lazy_init();
|
||||||
fs::lazy_init();
|
fs::lazy_init();
|
||||||
ipc::init();
|
ipc::init();
|
||||||
|
@ -186,6 +186,11 @@ pub struct HeaderPt2_64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_elf_header(elf_header: &ElfHeader) -> Result<()> {
|
fn check_elf_header(elf_header: &ElfHeader) -> Result<()> {
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
const EXPECTED_ELF_MACHINE: header::Machine = header::Machine::RISC_V;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
const EXPECTED_ELF_MACHINE: header::Machine = header::Machine::X86_64;
|
||||||
|
|
||||||
// 64bit
|
// 64bit
|
||||||
debug_assert_eq!(elf_header.pt1.class(), header::Class::SixtyFour);
|
debug_assert_eq!(elf_header.pt1.class(), header::Class::SixtyFour);
|
||||||
if elf_header.pt1.class() != header::Class::SixtyFour {
|
if elf_header.pt1.class() != header::Class::SixtyFour {
|
||||||
@ -201,14 +206,14 @@ fn check_elf_header(elf_header: &ElfHeader) -> Result<()> {
|
|||||||
// if elf_header.pt1.os_abi() != header::OsAbi::SystemV {
|
// if elf_header.pt1.os_abi() != header::OsAbi::SystemV {
|
||||||
// return Error::new(Errno::ENOEXEC);
|
// return Error::new(Errno::ENOEXEC);
|
||||||
// }
|
// }
|
||||||
// x86_64 architecture
|
if elf_header.pt2.machine.as_machine() != EXPECTED_ELF_MACHINE {
|
||||||
debug_assert_eq!(elf_header.pt2.machine.as_machine(), header::Machine::X86_64);
|
return_errno_with_message!(
|
||||||
if elf_header.pt2.machine.as_machine() != header::Machine::X86_64 {
|
Errno::ENOEXEC,
|
||||||
return_errno_with_message!(Errno::ENOEXEC, "Not x86_64 executable");
|
"Executable could not be run on this architecture"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Executable file or shared object
|
// Executable file or shared object
|
||||||
let elf_type = elf_header.pt2.type_.as_type();
|
let elf_type = elf_header.pt2.type_.as_type();
|
||||||
debug_assert!(elf_type == header::Type::Executable || elf_type == header::Type::SharedObject);
|
|
||||||
if elf_type != header::Type::Executable && elf_type != header::Type::SharedObject {
|
if elf_type != header::Type::Executable && elf_type != header::Type::SharedObject {
|
||||||
return_errno_with_message!(Errno::ENOEXEC, "Not executable file");
|
return_errno_with_message!(Errno::ENOEXEC, "Not executable file");
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,12 @@
|
|||||||
|
|
||||||
//! Implement the `syscall_dispatch` function and the const values of system call number such as `SYS_READ`.
|
//! Implement the `syscall_dispatch` function and the const values of system call number such as `SYS_READ`.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86;
|
pub mod x86;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use self::riscv::*;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use self::x86::*;
|
pub use self::x86::*;
|
||||||
|
273
kernel/src/syscall/arch/riscv.rs
Normal file
273
kernel/src/syscall/arch/riscv.rs
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use crate::syscall::{
|
||||||
|
accept::{sys_accept, sys_accept4},
|
||||||
|
access::sys_faccessat,
|
||||||
|
bind::sys_bind,
|
||||||
|
brk::sys_brk,
|
||||||
|
capget::sys_capget,
|
||||||
|
capset::sys_capset,
|
||||||
|
chdir::{sys_chdir, sys_fchdir},
|
||||||
|
chmod::{sys_fchmod, sys_fchmodat},
|
||||||
|
chown::{sys_fchown, sys_fchownat},
|
||||||
|
chroot::sys_chroot,
|
||||||
|
clock_gettime::sys_clock_gettime,
|
||||||
|
clone::{sys_clone, sys_clone3},
|
||||||
|
close::sys_close,
|
||||||
|
connect::sys_connect,
|
||||||
|
dup::{sys_dup, sys_dup3},
|
||||||
|
epoll::{sys_epoll_create1, sys_epoll_ctl, sys_epoll_pwait},
|
||||||
|
eventfd::sys_eventfd2,
|
||||||
|
execve::{sys_execve, sys_execveat},
|
||||||
|
exit::sys_exit,
|
||||||
|
exit_group::sys_exit_group,
|
||||||
|
fallocate::sys_fallocate,
|
||||||
|
fcntl::sys_fcntl,
|
||||||
|
flock::sys_flock,
|
||||||
|
fsync::{sys_fdatasync, sys_fsync},
|
||||||
|
futex::sys_futex,
|
||||||
|
getcwd::sys_getcwd,
|
||||||
|
getdents64::sys_getdents64,
|
||||||
|
getegid::sys_getegid,
|
||||||
|
geteuid::sys_geteuid,
|
||||||
|
getgid::sys_getgid,
|
||||||
|
getgroups::sys_getgroups,
|
||||||
|
getpeername::sys_getpeername,
|
||||||
|
getpgrp::sys_getpgrp,
|
||||||
|
getpid::sys_getpid,
|
||||||
|
getppid::sys_getppid,
|
||||||
|
getrandom::sys_getrandom,
|
||||||
|
getresgid::sys_getresgid,
|
||||||
|
getresuid::sys_getresuid,
|
||||||
|
getrusage::sys_getrusage,
|
||||||
|
getsid::sys_getsid,
|
||||||
|
getsockname::sys_getsockname,
|
||||||
|
getsockopt::sys_getsockopt,
|
||||||
|
gettid::sys_gettid,
|
||||||
|
gettimeofday::sys_gettimeofday,
|
||||||
|
getuid::sys_getuid,
|
||||||
|
impl_syscall_nums_and_dispatch_fn,
|
||||||
|
ioctl::sys_ioctl,
|
||||||
|
kill::sys_kill,
|
||||||
|
link::sys_linkat,
|
||||||
|
listen::sys_listen,
|
||||||
|
lseek::sys_lseek,
|
||||||
|
madvise::sys_madvise,
|
||||||
|
mkdir::sys_mkdirat,
|
||||||
|
mknod::sys_mknodat,
|
||||||
|
mmap::sys_mmap,
|
||||||
|
mount::sys_mount,
|
||||||
|
mprotect::sys_mprotect,
|
||||||
|
msync::sys_msync,
|
||||||
|
munmap::sys_munmap,
|
||||||
|
nanosleep::{sys_clock_nanosleep, sys_nanosleep},
|
||||||
|
open::sys_openat,
|
||||||
|
pipe::sys_pipe2,
|
||||||
|
prctl::sys_prctl,
|
||||||
|
pread64::sys_pread64,
|
||||||
|
preadv::{sys_preadv, sys_preadv2, sys_readv},
|
||||||
|
prlimit64::sys_prlimit64,
|
||||||
|
pselect6::sys_pselect6,
|
||||||
|
pwrite64::sys_pwrite64,
|
||||||
|
pwritev::{sys_pwritev, sys_pwritev2, sys_writev},
|
||||||
|
read::sys_read,
|
||||||
|
readlink::sys_readlinkat,
|
||||||
|
recvfrom::sys_recvfrom,
|
||||||
|
recvmsg::sys_recvmsg,
|
||||||
|
rename::sys_renameat,
|
||||||
|
rt_sigaction::sys_rt_sigaction,
|
||||||
|
rt_sigpending::sys_rt_sigpending,
|
||||||
|
rt_sigprocmask::sys_rt_sigprocmask,
|
||||||
|
rt_sigsuspend::sys_rt_sigsuspend,
|
||||||
|
sched_getaffinity::sys_sched_getaffinity,
|
||||||
|
sched_yield::sys_sched_yield,
|
||||||
|
semctl::sys_semctl,
|
||||||
|
semget::sys_semget,
|
||||||
|
semop::{sys_semop, sys_semtimedop},
|
||||||
|
sendfile::sys_sendfile,
|
||||||
|
sendmsg::sys_sendmsg,
|
||||||
|
sendto::sys_sendto,
|
||||||
|
set_get_priority::{sys_get_priority, sys_set_priority},
|
||||||
|
set_robust_list::sys_set_robust_list,
|
||||||
|
set_tid_address::sys_set_tid_address,
|
||||||
|
setfsgid::sys_setfsgid,
|
||||||
|
setfsuid::sys_setfsuid,
|
||||||
|
setgid::sys_setgid,
|
||||||
|
setgroups::sys_setgroups,
|
||||||
|
setitimer::{sys_getitimer, sys_setitimer},
|
||||||
|
setpgid::sys_setpgid,
|
||||||
|
setregid::sys_setregid,
|
||||||
|
setresgid::sys_setresgid,
|
||||||
|
setresuid::sys_setresuid,
|
||||||
|
setreuid::sys_setreuid,
|
||||||
|
setsid::sys_setsid,
|
||||||
|
setsockopt::sys_setsockopt,
|
||||||
|
setuid::sys_setuid,
|
||||||
|
shutdown::sys_shutdown,
|
||||||
|
sigaltstack::sys_sigaltstack,
|
||||||
|
socket::sys_socket,
|
||||||
|
socketpair::sys_socketpair,
|
||||||
|
stat::{sys_fstat, sys_fstatat},
|
||||||
|
statfs::{sys_fstatfs, sys_statfs},
|
||||||
|
symlink::sys_symlinkat,
|
||||||
|
sync::sys_sync,
|
||||||
|
tgkill::sys_tgkill,
|
||||||
|
timer_create::{sys_timer_create, sys_timer_delete},
|
||||||
|
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||||
|
truncate::{sys_ftruncate, sys_truncate},
|
||||||
|
umask::sys_umask,
|
||||||
|
umount::sys_umount,
|
||||||
|
uname::sys_uname,
|
||||||
|
unlink::sys_unlinkat,
|
||||||
|
utimens::sys_utimensat,
|
||||||
|
wait4::sys_wait4,
|
||||||
|
waitid::sys_waitid,
|
||||||
|
write::sys_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_syscall_nums_and_dispatch_fn! {
|
||||||
|
SYS_GETCWD = 17 => sys_getcwd(args[..2]);
|
||||||
|
SYS_EVENTFD2 = 19 => sys_eventfd2(args[..2]);
|
||||||
|
SYS_EPOLL_CREATE1 = 20 => sys_epoll_create1(args[..1]);
|
||||||
|
SYS_EPOLL_CTL = 21 => sys_epoll_ctl(args[..4]);
|
||||||
|
SYS_EPOLL_PWAIT = 22 => sys_epoll_pwait(args[..6]);
|
||||||
|
SYS_DUP = 23 => sys_dup(args[..1]);
|
||||||
|
SYS_DUP3 = 24 => sys_dup3(args[..3]);
|
||||||
|
SYS_FCNTL = 25 => sys_fcntl(args[..3]);
|
||||||
|
SYS_IOCTL = 29 => sys_ioctl(args[..3]);
|
||||||
|
SYS_FLOCK = 32 => sys_flock(args[..2]);
|
||||||
|
SYS_MKNODAT = 33 => sys_mknodat(args[..4]);
|
||||||
|
SYS_MKDIRAT = 34 => sys_mkdirat(args[..3]);
|
||||||
|
SYS_UNLINKAT = 35 => sys_unlinkat(args[..3]);
|
||||||
|
SYS_SYMLINKAT = 36 => sys_symlinkat(args[..3]);
|
||||||
|
SYS_LINKAT = 37 => sys_linkat(args[..5]);
|
||||||
|
SYS_RENAMEAT = 38 => sys_renameat(args[..4]);
|
||||||
|
SYS_UMOUNT = 39 => sys_umount(args[..2]);
|
||||||
|
SYS_MOUNT = 40 => sys_mount(args[..5]);
|
||||||
|
SYS_STATFS = 43 => sys_statfs(args[..2]);
|
||||||
|
SYS_FSTATFS = 44 => sys_fstatfs(args[..2]);
|
||||||
|
SYS_TRUNCATE = 45 => sys_truncate(args[..2]);
|
||||||
|
SYS_FTRUNCATE = 46 => sys_ftruncate(args[..2]);
|
||||||
|
SYS_FALLOCATE = 47 => sys_fallocate(args[..4]);
|
||||||
|
SYS_FACCESSAT = 48 => sys_faccessat(args[..3]);
|
||||||
|
SYS_CHDIR = 49 => sys_chdir(args[..1]);
|
||||||
|
SYS_FCHDIR = 50 => sys_fchdir(args[..1]);
|
||||||
|
SYS_CHROOT = 51 => sys_chroot(args[..1]);
|
||||||
|
SYS_FCHMOD = 52 => sys_fchmod(args[..2]);
|
||||||
|
SYS_FCHMODAT = 53 => sys_fchmodat(args[..3]);
|
||||||
|
SYS_FCHOWNAT = 54 => sys_fchownat(args[..5]);
|
||||||
|
SYS_FCHOWN = 55 => sys_fchown(args[..3]);
|
||||||
|
SYS_OPENAT = 56 => sys_openat(args[..4]);
|
||||||
|
SYS_CLOSE = 57 => sys_close(args[..1]);
|
||||||
|
SYS_PIPE2 = 59 => sys_pipe2(args[..2]);
|
||||||
|
SYS_GETDENTS64 = 61 => sys_getdents64(args[..3]);
|
||||||
|
SYS_LSEEK = 62 => sys_lseek(args[..3]);
|
||||||
|
SYS_READ = 63 => sys_read(args[..3]);
|
||||||
|
SYS_WRITE = 64 => sys_write(args[..3]);
|
||||||
|
SYS_READV = 65 => sys_readv(args[..3]);
|
||||||
|
SYS_WRITEV = 66 => sys_writev(args[..3]);
|
||||||
|
SYS_PREAD64 = 67 => sys_pread64(args[..4]);
|
||||||
|
SYS_PWRITE64 = 68 => sys_pwrite64(args[..4]);
|
||||||
|
SYS_PREADV = 69 => sys_preadv(args[..4]);
|
||||||
|
SYS_PWRITEV = 70 => sys_pwritev(args[..4]);
|
||||||
|
SYS_SENDFILE64 = 71 => sys_sendfile(args[..4]);
|
||||||
|
SYS_PSELECT6 = 72 => sys_pselect6(args[..6]);
|
||||||
|
SYS_READLINKAT = 78 => sys_readlinkat(args[..4]);
|
||||||
|
SYS_NEWFSTATAT = 79 => sys_fstatat(args[..4]);
|
||||||
|
SYS_NEWFSTAT = 80 => sys_fstat(args[..2]);
|
||||||
|
SYS_SYNC = 81 => sys_sync(args[..0]);
|
||||||
|
SYS_FSYNC = 82 => sys_fsync(args[..1]);
|
||||||
|
SYS_FDATASYNC = 83 => sys_fdatasync(args[..1]);
|
||||||
|
SYS_CAPGET = 90 => sys_capget(args[..2]);
|
||||||
|
SYS_CAPSET = 91 => sys_capset(args[..2]);
|
||||||
|
SYS_EXIT = 93 => sys_exit(args[..1]);
|
||||||
|
SYS_EXIT_GROUP = 94 => sys_exit_group(args[..1]);
|
||||||
|
SYS_WAITID = 95 => sys_waitid(args[..5]);
|
||||||
|
SYS_SET_TID_ADDRESS = 96 => sys_set_tid_address(args[..1]);
|
||||||
|
SYS_FUTEX = 98 => sys_futex(args[..6]);
|
||||||
|
SYS_SET_ROBUST_LIST = 99 => sys_set_robust_list(args[..2]);
|
||||||
|
SYS_NANOSLEEP = 101 => sys_nanosleep(args[..2]);
|
||||||
|
SYS_GETITIMER = 102 => sys_getitimer(args[..2]);
|
||||||
|
SYS_SETITIMER = 103 => sys_setitimer(args[..3]);
|
||||||
|
SYS_TIMER_CREATE = 107 => sys_timer_create(args[..3]);
|
||||||
|
SYS_TIMER_DELETE = 111 => sys_timer_delete(args[..1]);
|
||||||
|
SYS_SCHED_GETAFFINITY = 123 => sys_sched_getaffinity(args[..3]);
|
||||||
|
SYS_SCHED_YIELD = 124 => sys_sched_yield(args[..0]);
|
||||||
|
SYS_KILL = 129 => sys_kill(args[..2]);
|
||||||
|
SYS_TGKILL = 131 => sys_tgkill(args[..3]);
|
||||||
|
SYS_SIGALTSTACK = 132 => sys_sigaltstack(args[..2]);
|
||||||
|
SYS_RT_SIGSUSPEND = 133 => sys_rt_sigsuspend(args[..2]);
|
||||||
|
SYS_RT_SIGACTION = 134 => sys_rt_sigaction(args[..4]);
|
||||||
|
SYS_RT_SIGPROCMASK = 135 => sys_rt_sigprocmask(args[..4]);
|
||||||
|
SYS_RT_SIGPENDING = 136 => sys_rt_sigpending(args[..2]);
|
||||||
|
SYS_SET_PRIORITY = 140 => sys_set_priority(args[..3]);
|
||||||
|
SYS_GET_PRIORITY = 141 => sys_get_priority(args[..2]);
|
||||||
|
SYS_SETREGID = 143 => sys_setregid(args[..2]);
|
||||||
|
SYS_SETGID = 144 => sys_setgid(args[..1]);
|
||||||
|
SYS_SETREUID = 145 => sys_setreuid(args[..2]);
|
||||||
|
SYS_SETUID = 146 => sys_setuid(args[..1]);
|
||||||
|
SYS_SETRESUID = 147 => sys_setresuid(args[..3]);
|
||||||
|
SYS_GETRESUID = 148 => sys_getresuid(args[..3]);
|
||||||
|
SYS_SETRESGID = 149 => sys_setresgid(args[..3]);
|
||||||
|
SYS_GETRESGID = 150 => sys_getresgid(args[..3]);
|
||||||
|
SYS_SETFSUID = 151 => sys_setfsuid(args[..1]);
|
||||||
|
SYS_SETFSGID = 152 => sys_setfsgid(args[..1]);
|
||||||
|
SYS_SETPGID = 154 => sys_setpgid(args[..2]);
|
||||||
|
SYS_GETPGRP = 155 => sys_getpgrp(args[..0]);
|
||||||
|
SYS_GETSID = 156 => sys_getsid(args[..1]);
|
||||||
|
SYS_SETSID = 157 => sys_setsid(args[..0]);
|
||||||
|
SYS_GETGROUPS = 158 => sys_getgroups(args[..2]);
|
||||||
|
SYS_SETGROUPS = 159 => sys_setgroups(args[..2]);
|
||||||
|
SYS_NEWUNAME = 160 => sys_uname(args[..1]);
|
||||||
|
SYS_GETRUSAGE = 165 => sys_getrusage(args[..2]);
|
||||||
|
SYS_UMASK = 166 => sys_umask(args[..1]);
|
||||||
|
SYS_PRCTL = 167 => sys_prctl(args[..5]);
|
||||||
|
SYS_GETTIMEOFDAY = 169 => sys_gettimeofday(args[..1]);
|
||||||
|
SYS_GETPID = 172 => sys_getpid(args[..0]);
|
||||||
|
SYS_GETPPID = 173 => sys_getppid(args[..0]);
|
||||||
|
SYS_GETUID = 174 => sys_getuid(args[..0]);
|
||||||
|
SYS_GETEUID = 175 => sys_geteuid(args[..0]);
|
||||||
|
SYS_GETGID = 176 => sys_getgid(args[..0]);
|
||||||
|
SYS_GETEGID = 177 => sys_getegid(args[..0]);
|
||||||
|
SYS_GETTID = 178 => sys_gettid(args[..0]);
|
||||||
|
SYS_SEMGET = 190 => sys_semget(args[..3]);
|
||||||
|
SYS_SEMCTL = 191 => sys_semctl(args[..4]);
|
||||||
|
SYS_SEMOP = 193 => sys_semop(args[..3]);
|
||||||
|
SYS_SOCKET = 198 => sys_socket(args[..3]);
|
||||||
|
SYS_SOCKETPAIR = 199 => sys_socketpair(args[..4]);
|
||||||
|
SYS_BIND = 200 => sys_bind(args[..3]);
|
||||||
|
SYS_LISTEN = 201 => sys_listen(args[..2]);
|
||||||
|
SYS_ACCEPT = 202 => sys_accept(args[..3]);
|
||||||
|
SYS_CONNECT = 203 => sys_connect(args[..3]);
|
||||||
|
SYS_GETSOCKNAME = 204 => sys_getsockname(args[..3]);
|
||||||
|
SYS_GETPEERNAME = 205 => sys_getpeername(args[..3]);
|
||||||
|
SYS_SENDTO = 206 => sys_sendto(args[..6]);
|
||||||
|
SYS_RECVFROM = 207 => sys_recvfrom(args[..6]);
|
||||||
|
SYS_SETSOCKOPT = 208 => sys_setsockopt(args[..5]);
|
||||||
|
SYS_GETSOCKOPT = 209 => sys_getsockopt(args[..5]);
|
||||||
|
SYS_SHUTDOWN = 210 => sys_shutdown(args[..2]);
|
||||||
|
SYS_SENDMSG = 211 => sys_sendmsg(args[..3]);
|
||||||
|
SYS_RECVMSG = 212 => sys_recvmsg(args[..3]);
|
||||||
|
SYS_BRK = 214 => sys_brk(args[..1]);
|
||||||
|
SYS_MUNMAP = 215 => sys_munmap(args[..2]);
|
||||||
|
SYS_CLONE = 220 => sys_clone(args[..5], &user_ctx);
|
||||||
|
SYS_EXECVE = 221 => sys_execve(args[..3], &mut user_ctx);
|
||||||
|
SYS_MMAP = 222 => sys_mmap(args[..6]);
|
||||||
|
SYS_MPROTECT = 226 => sys_mprotect(args[..3]);
|
||||||
|
SYS_MSYNC = 227 => sys_msync(args[..3]);
|
||||||
|
SYS_MADVISE = 233 => sys_madvise(args[..3]);
|
||||||
|
SYS_ACCEPT4 = 242 => sys_accept4(args[..4]);
|
||||||
|
SYS_WAIT4 = 260 => sys_wait4(args[..4]);
|
||||||
|
SYS_PRLIMIT64 = 261 => sys_prlimit64(args[..4]);
|
||||||
|
SYS_GETRANDOM = 278 => sys_getrandom(args[..3]);
|
||||||
|
SYS_EXECVEAT = 281 => sys_execveat(args[..5], &mut user_ctx);
|
||||||
|
SYS_PREADV2 = 286 => sys_preadv2(args[..5]);
|
||||||
|
SYS_PWRITEV2 = 287 => sys_pwritev2(args[..5]);
|
||||||
|
SYS_CLOCK_GETTIME = 403 => sys_clock_gettime(args[..2]);
|
||||||
|
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
||||||
|
SYS_TIMER_GETTIME = 408 => sys_timer_gettime(args[..2]);
|
||||||
|
SYS_TIMER_SETTIME = 409 => sys_timer_settime(args[..4]);
|
||||||
|
SYS_UTIMENSAT = 412 => sys_utimensat(args[..4]);
|
||||||
|
SYS_SEMTIMEDOP = 420 => sys_semtimedop(args[..4]);
|
||||||
|
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
||||||
|
}
|
@ -37,6 +37,14 @@ pub fn init() {
|
|||||||
tail.copy_from_slice(&src[..n]);
|
tail.copy_from_slice(&src[..n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RNG.call_once(|| SpinLock::new(StdRng::from_seed(seed)));
|
||||||
|
} else if #[cfg(target_arch = "riscv64")] {
|
||||||
|
use rand::SeedableRng;
|
||||||
|
use ostd::arch::boot::DEVICE_TREE;
|
||||||
|
|
||||||
|
let chosen = DEVICE_TREE.get().unwrap().find_node("/chosen").unwrap();
|
||||||
|
let seed = chosen.property("rng-seed").unwrap().value.try_into().unwrap();
|
||||||
|
|
||||||
RNG.call_once(|| SpinLock::new(StdRng::from_seed(seed)));
|
RNG.call_once(|| SpinLock::new(StdRng::from_seed(seed)));
|
||||||
} else {
|
} else {
|
||||||
compile_error!("unsupported target");
|
compile_error!("unsupported target");
|
||||||
|
@ -78,7 +78,7 @@ pub fn new_base_crate(
|
|||||||
}
|
}
|
||||||
// TODO: currently just x86_64 works; add support for other architectures
|
// TODO: currently just x86_64 works; add support for other architectures
|
||||||
// here when OSTD is ready
|
// here when OSTD is ready
|
||||||
include_linker_script!(["x86_64.ld"]);
|
include_linker_script!(["x86_64.ld", "riscv64.ld"]);
|
||||||
|
|
||||||
// Overwrite the main.rs file
|
// Overwrite the main.rs file
|
||||||
let main_rs = include_str!("main.rs.template");
|
let main_rs = include_str!("main.rs.template");
|
||||||
|
64
osdk/src/base_crate/riscv64.ld.template
Normal file
64
osdk/src/base_crate/riscv64.ld.template
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
OUTPUT_ARCH(riscv)
|
||||||
|
ENTRY(_start)
|
||||||
|
KERNEL_LMA = 0x80200000;
|
||||||
|
KERNEL_VMA = 0xffffffff80200000;
|
||||||
|
KERNEL_VMA_OFFSET = KERNEL_VMA - KERNEL_LMA;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = KERNEL_VMA;
|
||||||
|
|
||||||
|
PROVIDE(__executable_start = .);
|
||||||
|
__kernel_start = .;
|
||||||
|
|
||||||
|
.text : AT(ADDR(.text) - KERNEL_VMA_OFFSET) {
|
||||||
|
*(.text.entry)
|
||||||
|
*(.text .text.*)
|
||||||
|
PROVIDE(__etext = .);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : AT(ADDR(.rodata) - KERNEL_VMA_OFFSET) { *(.rodata .rodata.*) }
|
||||||
|
|
||||||
|
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA_OFFSET) {
|
||||||
|
PROVIDE(__GNU_EH_FRAME_HDR = .);
|
||||||
|
KEEP(*(.eh_frame_hdr .eh_frame_hdr.*))
|
||||||
|
}
|
||||||
|
. = ALIGN(8);
|
||||||
|
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA_OFFSET) {
|
||||||
|
PROVIDE(__eh_frame = .);
|
||||||
|
KEEP(*(.eh_frame .eh_frame.*))
|
||||||
|
}
|
||||||
|
|
||||||
|
.init_array : AT(ADDR(.init_array) - KERNEL_VMA_OFFSET) {
|
||||||
|
__sinit_array = .;
|
||||||
|
KEEP(*(SORT(.init_array .init_array.*)))
|
||||||
|
__einit_array = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
. = DATA_SEGMENT_RELRO_END(0, .);
|
||||||
|
|
||||||
|
.data : AT(ADDR(.data) - KERNEL_VMA_OFFSET) { *(.data .data.*) }
|
||||||
|
|
||||||
|
# The CPU local data storage. It is readable and writable for the bootstrap
|
||||||
|
# processor, while it would be copied to other dynamically allocated memory
|
||||||
|
# areas for the application processors.
|
||||||
|
.cpu_local : AT(ADDR(.cpu_local) - KERNEL_VMA_OFFSET) {
|
||||||
|
__cpu_local_start = .;
|
||||||
|
KEEP(*(SORT(.cpu_local)))
|
||||||
|
__cpu_local_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* boot stack (in entry.S) */
|
||||||
|
.stack : AT(ADDR(.stack) - KERNEL_VMA_OFFSET) {
|
||||||
|
*(.bss.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : AT(ADDR(.bss) - KERNEL_VMA_OFFSET) {
|
||||||
|
__bss = .;
|
||||||
|
*(.bss .bss.*)
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
. = DATA_SEGMENT_END(.);
|
||||||
|
__kernel_end = .;
|
||||||
|
}
|
@ -57,6 +57,11 @@ iced-x86 = { version = "1.21.0", default-features = false, features = [
|
|||||||
], optional = true }
|
], optional = true }
|
||||||
tdx-guest = { version = "0.1.7", optional = true }
|
tdx-guest = { version = "0.1.7", optional = true }
|
||||||
|
|
||||||
|
[target.riscv64gc-unknown-none-elf.dependencies]
|
||||||
|
riscv = { version = "0.11.1", features = ["s-mode"] }
|
||||||
|
sbi-rt = "0.0.3"
|
||||||
|
fdt = { version = "0.1.5", features = ["pretty-printing"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["cvm_guest", "log_color"]
|
default = ["cvm_guest", "log_color"]
|
||||||
log_color = ["dep:owo-colors"]
|
log_color = ["dep:owo-colors"]
|
||||||
|
@ -4,8 +4,12 @@
|
|||||||
//!
|
//!
|
||||||
//! Each architecture that Asterinas supports may contain a submodule here.
|
//! Each architecture that Asterinas supports may contain a submodule here.
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub mod x86;
|
pub mod x86;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub use self::riscv::*;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use self::x86::*;
|
pub use self::x86::*;
|
||||||
|
62
ostd/src/arch/riscv/boot/boot.S
Normal file
62
ostd/src/arch/riscv/boot/boot.S
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* SPDX-License-Identifier: MPL-2.0 */
|
||||||
|
|
||||||
|
.section .text.entry
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
# Arguments passed from SBI:
|
||||||
|
# a0 = hart id
|
||||||
|
# a1 = device tree paddr (not touched)
|
||||||
|
|
||||||
|
# 1. enable paging
|
||||||
|
# setting up 1st pagetable
|
||||||
|
# entry = (PPN(boot_pagetable_2nd) << 10) | 0x01 # V
|
||||||
|
la t1, boot_pagetable
|
||||||
|
li t0, 8 * 511
|
||||||
|
add t1, t1, t0
|
||||||
|
la t0, boot_pagetable_2nd
|
||||||
|
srli t0, t0, 2
|
||||||
|
ori t0, t0, 0x01
|
||||||
|
sd t0, 0(t1)
|
||||||
|
|
||||||
|
la t0, boot_pagetable
|
||||||
|
li t1, 9 << 60
|
||||||
|
srli t0, t0, 12
|
||||||
|
or t0, t0, t1
|
||||||
|
csrw satp, t0
|
||||||
|
sfence.vma
|
||||||
|
|
||||||
|
# 2. set sp (BSP only)
|
||||||
|
lga sp, boot_stack_top
|
||||||
|
|
||||||
|
# 3. jump to rust riscv_boot
|
||||||
|
lga t0, riscv_boot
|
||||||
|
jr t0
|
||||||
|
|
||||||
|
|
||||||
|
.section .bss.stack
|
||||||
|
|
||||||
|
.globl boot_stack_bottom
|
||||||
|
boot_stack_bottom:
|
||||||
|
.space 0x40000 # 64 KiB
|
||||||
|
|
||||||
|
.globl boot_stack_top
|
||||||
|
boot_stack_top:
|
||||||
|
|
||||||
|
|
||||||
|
.section .data
|
||||||
|
|
||||||
|
.align 12
|
||||||
|
boot_pagetable:
|
||||||
|
.quad (0x00000 << 10) | 0xcf # VRWXAD
|
||||||
|
.zero 8 * 255
|
||||||
|
.quad (0x00000 << 10) | 0xcf # VRWXAD
|
||||||
|
.zero 8 * 254
|
||||||
|
.quad 0 # To-Be-Assign
|
||||||
|
|
||||||
|
boot_pagetable_2nd:
|
||||||
|
# 0x0000_00ff_8000_0000 -> 0x0000_0000_8000_0000
|
||||||
|
.zero 8 * 508
|
||||||
|
.quad (0x00000 << 10) | 0xcf # VRWXAD
|
||||||
|
.quad (0x40000 << 10) | 0xcf # VRWXAD
|
||||||
|
.quad (0x80000 << 10) | 0xcf # VRWXAD
|
||||||
|
.quad 0
|
132
ostd/src/arch/riscv/boot/mod.rs
Normal file
132
ostd/src/arch/riscv/boot/mod.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The RISC-V boot module defines the entrypoints of Asterinas.
|
||||||
|
|
||||||
|
pub mod smp;
|
||||||
|
|
||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use core::arch::global_asm;
|
||||||
|
|
||||||
|
use fdt::Fdt;
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
boot::{
|
||||||
|
kcmdline::KCmdlineArg,
|
||||||
|
memory_region::{non_overlapping_regions_from, MemoryRegion, MemoryRegionType},
|
||||||
|
BootloaderAcpiArg, BootloaderFramebufferArg,
|
||||||
|
},
|
||||||
|
early_println,
|
||||||
|
mm::paddr_to_vaddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
global_asm!(include_str!("boot.S"));
|
||||||
|
|
||||||
|
/// The Flattened Device Tree of the platform.
|
||||||
|
pub static DEVICE_TREE: Once<Fdt> = Once::new();
|
||||||
|
|
||||||
|
fn init_bootloader_name(bootloader_name: &'static Once<String>) {
|
||||||
|
bootloader_name.call_once(|| "Unknown".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_kernel_commandline(kernel_cmdline: &'static Once<KCmdlineArg>) {
|
||||||
|
let bootargs = DEVICE_TREE.get().unwrap().chosen().bootargs().unwrap_or("");
|
||||||
|
kernel_cmdline.call_once(|| bootargs.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_initramfs(initramfs: &'static Once<&'static [u8]>) {
|
||||||
|
let chosen = DEVICE_TREE.get().unwrap().find_node("/chosen").unwrap();
|
||||||
|
let initrd_start = chosen
|
||||||
|
.property("linux,initrd-start")
|
||||||
|
.unwrap()
|
||||||
|
.as_usize()
|
||||||
|
.unwrap();
|
||||||
|
let initrd_end = chosen
|
||||||
|
.property("linux,initrd-end")
|
||||||
|
.unwrap()
|
||||||
|
.as_usize()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let base_va = paddr_to_vaddr(initrd_start);
|
||||||
|
let length = initrd_end - initrd_start;
|
||||||
|
initramfs.call_once(|| unsafe { core::slice::from_raw_parts(base_va as *const u8, length) });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_acpi_arg(acpi: &'static Once<BootloaderAcpiArg>) {
|
||||||
|
acpi.call_once(|| BootloaderAcpiArg::NotProvided);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_framebuffer_info(_framebuffer_arg: &'static Once<BootloaderFramebufferArg>) {}
|
||||||
|
|
||||||
|
fn init_memory_regions(memory_regions: &'static Once<Vec<MemoryRegion>>) {
|
||||||
|
let mut regions = Vec::<MemoryRegion>::new();
|
||||||
|
|
||||||
|
for region in DEVICE_TREE.get().unwrap().memory().regions() {
|
||||||
|
if region.size.unwrap_or(0) > 0 {
|
||||||
|
regions.push(MemoryRegion::new(
|
||||||
|
region.starting_address as usize,
|
||||||
|
region.size.unwrap(),
|
||||||
|
MemoryRegionType::Usable,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(node) = DEVICE_TREE.get().unwrap().find_node("/reserved-memory") {
|
||||||
|
for child in node.children() {
|
||||||
|
if let Some(reg_iter) = child.reg() {
|
||||||
|
for region in reg_iter {
|
||||||
|
regions.push(MemoryRegion::new(
|
||||||
|
region.starting_address as usize,
|
||||||
|
region.size.unwrap(),
|
||||||
|
MemoryRegionType::Reserved,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the kernel region.
|
||||||
|
regions.push(MemoryRegion::kernel());
|
||||||
|
|
||||||
|
// Add the initramfs region.
|
||||||
|
let chosen = DEVICE_TREE.get().unwrap().find_node("/chosen").unwrap();
|
||||||
|
let initrd_start = chosen
|
||||||
|
.property("linux,initrd-start")
|
||||||
|
.unwrap()
|
||||||
|
.as_usize()
|
||||||
|
.unwrap();
|
||||||
|
let initrd_end = chosen
|
||||||
|
.property("linux,initrd-end")
|
||||||
|
.unwrap()
|
||||||
|
.as_usize()
|
||||||
|
.unwrap();
|
||||||
|
let length = initrd_end - initrd_start;
|
||||||
|
regions.push(MemoryRegion::new(
|
||||||
|
initrd_start,
|
||||||
|
length,
|
||||||
|
MemoryRegionType::Module,
|
||||||
|
));
|
||||||
|
|
||||||
|
memory_regions.call_once(|| non_overlapping_regions_from(regions.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The entry point of the Rust code portion of Asterinas.
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn riscv_boot(_hart_id: usize, device_tree_paddr: usize) -> ! {
|
||||||
|
early_println!("Enter riscv_boot");
|
||||||
|
|
||||||
|
let device_tree_ptr = paddr_to_vaddr(device_tree_paddr) as *const u8;
|
||||||
|
let fdt = unsafe { fdt::Fdt::from_ptr(device_tree_ptr).unwrap() };
|
||||||
|
DEVICE_TREE.call_once(|| fdt);
|
||||||
|
|
||||||
|
crate::boot::register_boot_init_callbacks(
|
||||||
|
init_bootloader_name,
|
||||||
|
init_kernel_commandline,
|
||||||
|
init_initramfs,
|
||||||
|
init_acpi_arg,
|
||||||
|
init_framebuffer_info,
|
||||||
|
init_memory_regions,
|
||||||
|
);
|
||||||
|
|
||||||
|
crate::boot::call_ostd_main();
|
||||||
|
}
|
11
ostd/src/arch/riscv/boot/smp.rs
Normal file
11
ostd/src/arch/riscv/boot/smp.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Multiprocessor Boot Support
|
||||||
|
|
||||||
|
pub(crate) fn get_num_processors() -> Option<u32> {
|
||||||
|
Some(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn bringup_all_aps() {
|
||||||
|
// TODO
|
||||||
|
}
|
23
ostd/src/arch/riscv/cpu/local.rs
Normal file
23
ostd/src/arch/riscv/cpu/local.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Architecture dependent CPU-local information utilities.
|
||||||
|
|
||||||
|
pub(crate) unsafe fn set_base(addr: u64) {
|
||||||
|
core::arch::asm!(
|
||||||
|
"mv gp, {addr}",
|
||||||
|
addr = in(reg) addr,
|
||||||
|
options(preserves_flags, nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_base() -> u64 {
|
||||||
|
let mut gp;
|
||||||
|
unsafe {
|
||||||
|
core::arch::asm!(
|
||||||
|
"mv {gp}, gp",
|
||||||
|
gp = out(reg) gp,
|
||||||
|
options(preserves_flags, nostack)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gp
|
||||||
|
}
|
230
ostd/src/arch/riscv/cpu/mod.rs
Normal file
230
ostd/src/arch/riscv/cpu/mod.rs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! CPU
|
||||||
|
|
||||||
|
pub mod local;
|
||||||
|
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use riscv::register::scause::{Exception, Trap};
|
||||||
|
|
||||||
|
pub use super::trap::GeneralRegs as RawGeneralRegs;
|
||||||
|
use super::trap::{TrapFrame, UserContext as RawUserContext};
|
||||||
|
use crate::user::{ReturnReason, UserContextApi, UserContextApiInternal};
|
||||||
|
|
||||||
|
/// Cpu context, including both general-purpose registers and floating-point registers.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct UserContext {
|
||||||
|
user_context: RawUserContext,
|
||||||
|
trap: Trap,
|
||||||
|
fp_regs: (), // TODO
|
||||||
|
cpu_exception_info: CpuExceptionInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CPU exception information.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CpuExceptionInfo {
|
||||||
|
/// The type of the exception.
|
||||||
|
pub code: Exception,
|
||||||
|
/// The error code associated with the exception.
|
||||||
|
pub page_fault_addr: usize,
|
||||||
|
pub error_code: usize, // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UserContext {
|
||||||
|
fn default() -> Self {
|
||||||
|
UserContext {
|
||||||
|
user_context: RawUserContext::default(),
|
||||||
|
trap: Trap::Exception(Exception::Unknown),
|
||||||
|
fp_regs: (),
|
||||||
|
cpu_exception_info: CpuExceptionInfo::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CpuExceptionInfo {
|
||||||
|
fn default() -> Self {
|
||||||
|
CpuExceptionInfo {
|
||||||
|
code: Exception::Unknown,
|
||||||
|
page_fault_addr: 0,
|
||||||
|
error_code: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuExceptionInfo {
|
||||||
|
/// Get corresponding CPU exception
|
||||||
|
pub fn cpu_exception(&self) -> CpuException {
|
||||||
|
self.code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContext {
|
||||||
|
/// Returns a reference to the general registers.
|
||||||
|
pub fn general_regs(&self) -> &RawGeneralRegs {
|
||||||
|
&self.user_context.general
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the general registers
|
||||||
|
pub fn general_regs_mut(&mut self) -> &mut RawGeneralRegs {
|
||||||
|
&mut self.user_context.general
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the trap information.
|
||||||
|
pub fn trap_information(&self) -> &CpuExceptionInfo {
|
||||||
|
&self.cpu_exception_info
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the floating point registers
|
||||||
|
pub fn fp_regs(&self) -> &() {
|
||||||
|
&self.fp_regs
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the floating point registers
|
||||||
|
pub fn fp_regs_mut(&mut self) -> &mut () {
|
||||||
|
&mut self.fp_regs
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.set_tp(tls)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
self.tp()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Activates thread-local storage pointer on the current CPU.
|
||||||
|
pub fn activate_tls_pointer(&self) {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContextApiInternal for UserContext {
|
||||||
|
fn execute<F>(&mut self, mut has_kernel_event: F) -> ReturnReason
|
||||||
|
where
|
||||||
|
F: FnMut() -> bool,
|
||||||
|
{
|
||||||
|
let ret = loop {
|
||||||
|
self.user_context.run();
|
||||||
|
match riscv::register::scause::read().cause() {
|
||||||
|
Trap::Interrupt(_) => todo!(),
|
||||||
|
Trap::Exception(Exception::UserEnvCall) => {
|
||||||
|
self.user_context.sepc += 4;
|
||||||
|
break ReturnReason::UserSyscall;
|
||||||
|
}
|
||||||
|
Trap::Exception(e) => {
|
||||||
|
let stval = riscv::register::stval::read();
|
||||||
|
log::trace!("Exception, scause: {e:?}, stval: {stval:#x?}");
|
||||||
|
self.cpu_exception_info = CpuExceptionInfo {
|
||||||
|
code: e,
|
||||||
|
page_fault_addr: stval,
|
||||||
|
error_code: 0,
|
||||||
|
};
|
||||||
|
break ReturnReason::UserException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_kernel_event() {
|
||||||
|
break ReturnReason::KernelEvent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
crate::arch::irq::enable_local();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_trap_frame(&self) -> TrapFrame {
|
||||||
|
TrapFrame {
|
||||||
|
general: self.user_context.general,
|
||||||
|
sstatus: self.user_context.sstatus,
|
||||||
|
sepc: self.user_context.sepc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContextApi for UserContext {
|
||||||
|
fn trap_number(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trap_error_code(&self) -> usize {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instruction_pointer(&self) -> usize {
|
||||||
|
self.user_context.sepc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_instruction_pointer(&mut self, ip: usize) {
|
||||||
|
self.user_context.set_ip(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_pointer(&self) -> usize {
|
||||||
|
self.user_context.get_sp()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack_pointer(&mut self, sp: usize) {
|
||||||
|
self.user_context.set_sp(sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! cpu_context_impl_getter_setter {
|
||||||
|
( $( [ $field: ident, $setter_name: ident] ),*) => {
|
||||||
|
impl UserContext {
|
||||||
|
$(
|
||||||
|
#[doc = concat!("Gets the value of ", stringify!($field))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn $field(&self) -> usize {
|
||||||
|
self.user_context.general.$field
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = concat!("Sets the value of ", stringify!($field))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn $setter_name(&mut self, $field: usize) {
|
||||||
|
self.user_context.general.$field = $field;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_context_impl_getter_setter!(
|
||||||
|
[ra, set_ra],
|
||||||
|
[sp, set_sp],
|
||||||
|
[gp, set_gp],
|
||||||
|
[tp, set_tp],
|
||||||
|
[t0, set_t0],
|
||||||
|
[t1, set_t1],
|
||||||
|
[t2, set_t2],
|
||||||
|
[s0, set_s0],
|
||||||
|
[s1, set_s1],
|
||||||
|
[a0, set_a0],
|
||||||
|
[a1, set_a1],
|
||||||
|
[a2, set_a2],
|
||||||
|
[a3, set_a3],
|
||||||
|
[a4, set_a4],
|
||||||
|
[a5, set_a5],
|
||||||
|
[a6, set_a6],
|
||||||
|
[a7, set_a7],
|
||||||
|
[s2, set_s2],
|
||||||
|
[s3, set_s3],
|
||||||
|
[s4, set_s4],
|
||||||
|
[s5, set_s5],
|
||||||
|
[s6, set_s6],
|
||||||
|
[s7, set_s7],
|
||||||
|
[s8, set_s8],
|
||||||
|
[s9, set_s9],
|
||||||
|
[s10, set_s10],
|
||||||
|
[s11, set_s11],
|
||||||
|
[t3, set_t3],
|
||||||
|
[t4, set_t4],
|
||||||
|
[t5, set_t5],
|
||||||
|
[t6, set_t6]
|
||||||
|
);
|
||||||
|
|
||||||
|
/// CPU exception.
|
||||||
|
pub type CpuException = Exception;
|
84
ostd/src/arch/riscv/device/io_port.rs
Normal file
84
ostd/src/arch/riscv/device/io_port.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! I/O port access.
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
pub struct WriteOnlyAccess;
|
||||||
|
pub struct ReadWriteAccess;
|
||||||
|
|
||||||
|
pub trait IoPortWriteAccess {}
|
||||||
|
pub trait IoPortReadAccess {}
|
||||||
|
|
||||||
|
impl IoPortWriteAccess for WriteOnlyAccess {}
|
||||||
|
impl IoPortWriteAccess for ReadWriteAccess {}
|
||||||
|
impl IoPortReadAccess for ReadWriteAccess {}
|
||||||
|
|
||||||
|
pub trait PortRead: Sized {
|
||||||
|
unsafe fn read_from_port(_port: u16) -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PortWrite: Sized {
|
||||||
|
unsafe fn write_to_port(_port: u16, _value: Self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PortRead for u8 {}
|
||||||
|
impl PortWrite for u8 {}
|
||||||
|
impl PortRead for u16 {}
|
||||||
|
impl PortWrite for u16 {}
|
||||||
|
impl PortRead for u32 {}
|
||||||
|
impl PortWrite for u32 {}
|
||||||
|
|
||||||
|
/// An I/O port, representing a specific address in the I/O address of x86.
|
||||||
|
///
|
||||||
|
/// The following code shows and example to read and write u32 value to an I/O port:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// static PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x12) };
|
||||||
|
///
|
||||||
|
/// fn port_value_increase(){
|
||||||
|
/// PORT.write(PORT.read() + 1)
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub struct IoPort<T, A> {
|
||||||
|
port: u16,
|
||||||
|
value_marker: PhantomData<T>,
|
||||||
|
access_marker: PhantomData<A>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A> IoPort<T, A> {
|
||||||
|
/// Create an I/O port.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is marked unsafe as creating an I/O port is considered
|
||||||
|
/// a privileged operation.
|
||||||
|
pub const unsafe fn new(port: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
port,
|
||||||
|
value_marker: PhantomData,
|
||||||
|
access_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PortRead, A: IoPortReadAccess> IoPort<T, A> {
|
||||||
|
/// Reads from the I/O port
|
||||||
|
#[inline]
|
||||||
|
pub fn read(&self) -> T {
|
||||||
|
unsafe { PortRead::read_from_port(self.port) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PortWrite, A: IoPortWriteAccess> IoPort<T, A> {
|
||||||
|
/// Writes to the I/O port
|
||||||
|
#[inline]
|
||||||
|
pub fn write(&self, value: T) {
|
||||||
|
unsafe { PortWrite::write_to_port(self.port, value) }
|
||||||
|
}
|
||||||
|
}
|
6
ostd/src/arch/riscv/device/mod.rs
Normal file
6
ostd/src/arch/riscv/device/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Device-related APIs.
|
||||||
|
//! This module mainly contains the APIs that should exposed to the device driver like PCI, RTC
|
||||||
|
|
||||||
|
pub mod io_port;
|
33
ostd/src/arch/riscv/iommu/mod.rs
Normal file
33
ostd/src/arch/riscv/iommu/mod.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The IOMMU support.
|
||||||
|
|
||||||
|
use crate::mm::{dma::Daddr, Paddr};
|
||||||
|
|
||||||
|
/// An enumeration representing possible errors related to IOMMU.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum IommuError {
|
||||||
|
/// No IOMMU is available.
|
||||||
|
NoIommu,
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Mapping an incorrect address may lead to a kernel data leak.
|
||||||
|
pub(crate) unsafe fn map(_daddr: Daddr, _paddr: Paddr) -> Result<(), IommuError> {
|
||||||
|
Err(IommuError::NoIommu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn unmap(_daddr: Daddr) -> Result<(), IommuError> {
|
||||||
|
Err(IommuError::NoIommu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn init() -> Result<(), IommuError> {
|
||||||
|
// TODO: We will support IOMMU on RISC-V
|
||||||
|
Err(IommuError::NoIommu)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn has_dma_remapping() -> bool {
|
||||||
|
false
|
||||||
|
}
|
150
ostd/src/arch/riscv/irq.rs
Normal file
150
ostd/src/arch/riscv/irq.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Interrupts.
|
||||||
|
|
||||||
|
use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
|
use id_alloc::IdAlloc;
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
sync::{Mutex, PreemptDisabled, SpinLock, SpinLockGuard},
|
||||||
|
trap::TrapFrame,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The global allocator for software defined IRQ lines.
|
||||||
|
pub(crate) static IRQ_ALLOCATOR: Once<SpinLock<IdAlloc>> = Once::new();
|
||||||
|
|
||||||
|
pub(crate) static IRQ_LIST: Once<Vec<IrqLine>> = Once::new();
|
||||||
|
|
||||||
|
pub(crate) fn init() {
|
||||||
|
let mut list: Vec<IrqLine> = Vec::new();
|
||||||
|
for i in 0..256 {
|
||||||
|
list.push(IrqLine {
|
||||||
|
irq_num: i as u8,
|
||||||
|
callback_list: SpinLock::new(Vec::new()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
IRQ_LIST.call_once(|| list);
|
||||||
|
CALLBACK_ID_ALLOCATOR.call_once(|| Mutex::new(IdAlloc::with_capacity(256)));
|
||||||
|
IRQ_ALLOCATOR.call_once(|| SpinLock::new(IdAlloc::with_capacity(256)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enable_local() {
|
||||||
|
unsafe { riscv::interrupt::enable() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn disable_local() {
|
||||||
|
riscv::interrupt::disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_local_enabled() -> bool {
|
||||||
|
riscv::register::sstatus::read().sie()
|
||||||
|
}
|
||||||
|
|
||||||
|
static CALLBACK_ID_ALLOCATOR: Once<Mutex<IdAlloc>> = Once::new();
|
||||||
|
|
||||||
|
pub struct CallbackElement {
|
||||||
|
function: Box<dyn Fn(&TrapFrame) + Send + Sync + 'static>,
|
||||||
|
id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CallbackElement {
|
||||||
|
pub fn call(&self, element: &TrapFrame) {
|
||||||
|
self.function.call((element,));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for CallbackElement {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("CallbackElement")
|
||||||
|
.field("id", &self.id)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An interrupt request (IRQ) line.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct IrqLine {
|
||||||
|
pub(crate) irq_num: u8,
|
||||||
|
pub(crate) callback_list: SpinLock<Vec<CallbackElement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqLine {
|
||||||
|
/// Acquire an interrupt request line.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function is marked unsafe as manipulating interrupt lines is
|
||||||
|
/// considered a dangerous operation.
|
||||||
|
#[allow(clippy::redundant_allocation)]
|
||||||
|
pub unsafe fn acquire(irq_num: u8) -> Arc<&'static Self> {
|
||||||
|
Arc::new(IRQ_LIST.get().unwrap().get(irq_num as usize).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the IRQ number.
|
||||||
|
pub fn num(&self) -> u8 {
|
||||||
|
self.irq_num
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn callback_list(
|
||||||
|
&self,
|
||||||
|
) -> SpinLockGuard<alloc::vec::Vec<CallbackElement>, PreemptDisabled> {
|
||||||
|
self.callback_list.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register a callback that will be invoked when the IRQ is active.
|
||||||
|
///
|
||||||
|
/// A handle to the callback is returned. Dropping the handle
|
||||||
|
/// automatically unregisters the callback.
|
||||||
|
///
|
||||||
|
/// For each IRQ line, multiple callbacks may be registered.
|
||||||
|
pub fn on_active<F>(&self, callback: F) -> IrqCallbackHandle
|
||||||
|
where
|
||||||
|
F: Fn(&TrapFrame) + Sync + Send + 'static,
|
||||||
|
{
|
||||||
|
let allocate_id = CALLBACK_ID_ALLOCATOR.get().unwrap().lock().alloc().unwrap();
|
||||||
|
self.callback_list.lock().push(CallbackElement {
|
||||||
|
function: Box::new(callback),
|
||||||
|
id: allocate_id,
|
||||||
|
});
|
||||||
|
IrqCallbackHandle {
|
||||||
|
irq_num: self.irq_num,
|
||||||
|
id: allocate_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The handle to a registered callback for a IRQ line.
|
||||||
|
///
|
||||||
|
/// When the handle is dropped, the callback will be unregistered automatically.
|
||||||
|
#[must_use]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IrqCallbackHandle {
|
||||||
|
irq_num: u8,
|
||||||
|
id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for IrqCallbackHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let mut a = IRQ_LIST
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.get(self.irq_num as usize)
|
||||||
|
.unwrap()
|
||||||
|
.callback_list
|
||||||
|
.lock();
|
||||||
|
a.retain(|item| item.id != self.id);
|
||||||
|
CALLBACK_ID_ALLOCATOR.get().unwrap().lock().free(self.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a general inter-processor interrupt (IPI) to the specified CPU.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller must ensure that the CPU ID and the interrupt number corresponds
|
||||||
|
/// to a safe function to call.
|
||||||
|
pub(crate) unsafe fn send_ipi(cpu_id: u32, irq_num: u8) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
229
ostd/src/arch/riscv/mm/mod.rs
Normal file
229
ostd/src/arch/riscv/mm/mod.rs
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::fmt;
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
mm::{
|
||||||
|
page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags as PrivFlags},
|
||||||
|
page_table::PageTableEntryTrait,
|
||||||
|
Paddr, PagingConstsTrait, PagingLevel, Vaddr, PAGE_SIZE,
|
||||||
|
},
|
||||||
|
Pod,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) const NR_ENTRIES_PER_PAGE: usize = 512;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct PagingConsts {}
|
||||||
|
|
||||||
|
impl PagingConstsTrait for PagingConsts {
|
||||||
|
const BASE_PAGE_SIZE: usize = 4096;
|
||||||
|
const NR_LEVELS: PagingLevel = 4;
|
||||||
|
const ADDRESS_WIDTH: usize = 48;
|
||||||
|
const HIGHEST_TRANSLATION_LEVEL: PagingLevel = 4;
|
||||||
|
const PTE_SIZE: usize = core::mem::size_of::<PageTableEntry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
#[derive(Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
/// Possible flags for a page table entry.
|
||||||
|
pub struct PageTableFlags: usize {
|
||||||
|
/// Specifies whether the mapped frame or page table is valid.
|
||||||
|
const VALID = 1 << 0;
|
||||||
|
/// Controls whether reads to the mapped frames are allowed.
|
||||||
|
const READABLE = 1 << 1;
|
||||||
|
/// Controls whether writes to the mapped frames are allowed.
|
||||||
|
const WRITABLE = 1 << 2;
|
||||||
|
/// Controls whether execution code in the mapped frames are allowed.
|
||||||
|
const EXECUTABLE = 1 << 3;
|
||||||
|
/// Controls whether accesses from userspace (i.e. U-mode) are permitted.
|
||||||
|
const USER = 1 << 4;
|
||||||
|
/// Indicates that the mapping is present in all address spaces, so it isn't flushed from
|
||||||
|
/// the TLB on an address space switch.
|
||||||
|
const GLOBAL = 1 << 5;
|
||||||
|
/// Whether the memory area represented by this entry is accessed.
|
||||||
|
const ACCESSED = 1 << 6;
|
||||||
|
/// Whether the memory area represented by this entry is modified.
|
||||||
|
const DIRTY = 1 << 7;
|
||||||
|
// PBMT: Non-cacheable, idempotent, weakly-ordered (RVWMO), main memory
|
||||||
|
const PBMT_NC = 1 << 61;
|
||||||
|
// PBMT: Non-cacheable, non-idempotent, strongly-ordered (I/O ordering), I/O
|
||||||
|
const PBMT_IO = 1 << 62;
|
||||||
|
/// Naturally aligned power-of-2
|
||||||
|
const NAPOT = 1 << 63;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn tlb_flush_addr(vaddr: Vaddr) {
|
||||||
|
unsafe {
|
||||||
|
riscv::asm::sfence_vma(0, vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn tlb_flush_addr_range(range: &Range<Vaddr>) {
|
||||||
|
for vaddr in range.clone().step_by(PAGE_SIZE) {
|
||||||
|
tlb_flush_addr(vaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn tlb_flush_all_excluding_global() {
|
||||||
|
// TODO: excluding global?
|
||||||
|
riscv::asm::sfence_vma_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn tlb_flush_all_including_global() {
|
||||||
|
riscv::asm::sfence_vma_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct PageTableEntry(usize);
|
||||||
|
|
||||||
|
/// Activate the given level 4 page table.
|
||||||
|
///
|
||||||
|
/// "satp" register doesn't have a field that encodes the cache policy,
|
||||||
|
/// so `_root_pt_cache` is ignored.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Changing the level 4 page table is unsafe, because it's possible to violate memory safety by
|
||||||
|
/// changing the page mapping.
|
||||||
|
pub unsafe fn activate_page_table(root_paddr: Paddr, _root_pt_cache: CachePolicy) {
|
||||||
|
assert!(root_paddr % PagingConsts::BASE_PAGE_SIZE == 0);
|
||||||
|
let ppn = root_paddr >> 12;
|
||||||
|
riscv::register::satp::set(riscv::register::satp::Mode::Sv48, 0, ppn);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_page_table_paddr() -> Paddr {
|
||||||
|
riscv::register::satp::read().ppn() << 12
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableEntry {
|
||||||
|
const PHYS_ADDR_MASK: usize = 0x003F_FFFF_FFFF_FC00;
|
||||||
|
|
||||||
|
fn new_paddr(paddr: Paddr) -> Self {
|
||||||
|
let ppn = paddr >> 12;
|
||||||
|
Self(ppn << 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a bit-flag bits `val` in the representation of `from` to `to` in bits.
|
||||||
|
macro_rules! parse_flags {
|
||||||
|
($val:expr, $from:expr, $to:expr) => {
|
||||||
|
($val as usize & $from.bits() as usize) >> $from.bits().ilog2() << $to.bits().ilog2()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PageTableEntryTrait for PageTableEntry {
|
||||||
|
fn is_present(&self) -> bool {
|
||||||
|
self.0 & PageTableFlags::VALID.bits() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_page(paddr: Paddr, _level: PagingLevel, prop: PageProperty) -> Self {
|
||||||
|
let mut pte = Self::new_paddr(paddr);
|
||||||
|
pte.set_prop(prop);
|
||||||
|
pte
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_pt(paddr: Paddr) -> Self {
|
||||||
|
// In RISC-V, non-leaf PTE should have RWX = 000,
|
||||||
|
// and D, A, and U are reserved for future standard use.
|
||||||
|
let pte = Self::new_paddr(paddr);
|
||||||
|
PageTableEntry(pte.0 | PageTableFlags::VALID.bits())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paddr(&self) -> Paddr {
|
||||||
|
let ppn = (self.0 & Self::PHYS_ADDR_MASK) >> 10;
|
||||||
|
ppn << 12
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prop(&self) -> PageProperty {
|
||||||
|
let flags = parse_flags!(self.0, PageTableFlags::READABLE, PageFlags::R)
|
||||||
|
| parse_flags!(self.0, PageTableFlags::WRITABLE, PageFlags::W)
|
||||||
|
| parse_flags!(self.0, PageTableFlags::EXECUTABLE, PageFlags::X)
|
||||||
|
| parse_flags!(self.0, PageTableFlags::ACCESSED, PageFlags::ACCESSED)
|
||||||
|
| parse_flags!(self.0, PageTableFlags::DIRTY, PageFlags::DIRTY);
|
||||||
|
let priv_flags = parse_flags!(self.0, PageTableFlags::USER, PrivFlags::USER)
|
||||||
|
| parse_flags!(self.0, PageTableFlags::GLOBAL, PrivFlags::GLOBAL);
|
||||||
|
|
||||||
|
let cache = if self.0 & PageTableFlags::PBMT_IO.bits() != 0 {
|
||||||
|
CachePolicy::Uncacheable
|
||||||
|
} else {
|
||||||
|
CachePolicy::Writeback
|
||||||
|
};
|
||||||
|
|
||||||
|
PageProperty {
|
||||||
|
flags: PageFlags::from_bits(flags as u8).unwrap(),
|
||||||
|
cache,
|
||||||
|
priv_flags: PrivFlags::from_bits(priv_flags as u8).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_prop(&mut self, prop: PageProperty) {
|
||||||
|
let mut flags = PageTableFlags::VALID.bits()
|
||||||
|
| parse_flags!(prop.flags.bits(), PageFlags::R, PageTableFlags::READABLE)
|
||||||
|
| parse_flags!(prop.flags.bits(), PageFlags::W, PageTableFlags::WRITABLE)
|
||||||
|
| parse_flags!(prop.flags.bits(), PageFlags::X, PageTableFlags::EXECUTABLE)
|
||||||
|
| parse_flags!(
|
||||||
|
prop.priv_flags.bits(),
|
||||||
|
PrivFlags::USER,
|
||||||
|
PageTableFlags::USER
|
||||||
|
)
|
||||||
|
| parse_flags!(
|
||||||
|
prop.priv_flags.bits(),
|
||||||
|
PrivFlags::GLOBAL,
|
||||||
|
PageTableFlags::GLOBAL
|
||||||
|
);
|
||||||
|
|
||||||
|
match prop.cache {
|
||||||
|
CachePolicy::Writeback => (),
|
||||||
|
CachePolicy::Uncacheable => {
|
||||||
|
// Currently, Asterinas uses `Uncacheable` for I/O memory.
|
||||||
|
flags |= PageTableFlags::PBMT_IO.bits()
|
||||||
|
}
|
||||||
|
_ => panic!("unsupported cache policy"),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.0 = (self.0 & Self::PHYS_ADDR_MASK) | flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_last(&self, level: PagingLevel) -> bool {
|
||||||
|
let rwx = PageTableFlags::READABLE | PageTableFlags::WRITABLE | PageTableFlags::EXECUTABLE;
|
||||||
|
level == 1 || (self.0 & rwx.bits()) != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for PageTableEntry {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut f = f.debug_struct("PageTableEntry");
|
||||||
|
f.field("raw", &format_args!("{:#x}", self.0))
|
||||||
|
.field("paddr", &format_args!("{:#x}", self.paddr()))
|
||||||
|
.field("present", &self.is_present())
|
||||||
|
.field(
|
||||||
|
"flags",
|
||||||
|
&PageTableFlags::from_bits_truncate(self.0 & !Self::PHYS_ADDR_MASK),
|
||||||
|
)
|
||||||
|
.field("prop", &self.prop())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn __memcpy_fallible(dst: *mut u8, src: *const u8, size: usize) -> usize {
|
||||||
|
// TODO: implement fallible
|
||||||
|
unsafe {
|
||||||
|
riscv::register::sstatus::set_sum();
|
||||||
|
}
|
||||||
|
unsafe { core::ptr::copy(src, dst, size) };
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn __memset_fallible(dst: *mut u8, value: u8, size: usize) -> usize {
|
||||||
|
// TODO: implement fallible
|
||||||
|
unsafe {
|
||||||
|
riscv::register::sstatus::set_sum();
|
||||||
|
}
|
||||||
|
unsafe { core::ptr::write_bytes(dst, value, size) };
|
||||||
|
0
|
||||||
|
}
|
69
ostd/src/arch/riscv/mod.rs
Normal file
69
ostd/src/arch/riscv/mod.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Platform-specific code for the RISC-V platform.
|
||||||
|
|
||||||
|
pub mod boot;
|
||||||
|
pub(crate) mod cpu;
|
||||||
|
pub mod device;
|
||||||
|
pub mod iommu;
|
||||||
|
pub(crate) mod irq;
|
||||||
|
pub(crate) mod mm;
|
||||||
|
pub(crate) mod pci;
|
||||||
|
pub mod qemu;
|
||||||
|
pub mod serial;
|
||||||
|
pub mod task;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod trap;
|
||||||
|
|
||||||
|
use core::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
#[cfg(feature = "cvm_guest")]
|
||||||
|
pub(crate) fn init_cvm_guest() {
|
||||||
|
// Unimplemented, no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn init_on_bsp() {
|
||||||
|
// SAFETY: this function is only called once on BSP.
|
||||||
|
unsafe {
|
||||||
|
trap::init(true);
|
||||||
|
}
|
||||||
|
irq::init();
|
||||||
|
|
||||||
|
// SAFETY: they are only called once on BSP and ACPI has been initialized.
|
||||||
|
unsafe {
|
||||||
|
crate::cpu::init_num_cpus();
|
||||||
|
crate::cpu::set_this_cpu_id(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: no CPU local objects have been accessed by this far. And
|
||||||
|
// we are on the BSP.
|
||||||
|
unsafe { crate::cpu::local::init_on_bsp() };
|
||||||
|
|
||||||
|
crate::boot::smp::boot_all_aps();
|
||||||
|
|
||||||
|
timer::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn init_on_ap() {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn interrupts_ack(irq_number: usize) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the frequency of TSC. The unit is Hz.
|
||||||
|
pub fn tsc_freq() -> u64 {
|
||||||
|
timer::TIMEBASE_FREQ.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the current value of the processor’s time-stamp counter (TSC).
|
||||||
|
pub fn read_tsc() -> u64 {
|
||||||
|
riscv::register::time::read64()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn enable_cpu_features() {
|
||||||
|
unsafe {
|
||||||
|
riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Clean);
|
||||||
|
}
|
||||||
|
}
|
8
ostd/src/arch/riscv/pci.rs
Normal file
8
ostd/src/arch/riscv/pci.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! PCI bus io port
|
||||||
|
|
||||||
|
use super::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
||||||
|
|
||||||
|
pub static PCI_ADDRESS_PORT: IoPort<u32, WriteOnlyAccess> = unsafe { IoPort::new(0x0) };
|
||||||
|
pub static PCI_DATA_PORT: IoPort<u32, ReadWriteAccess> = unsafe { IoPort::new(0x0) };
|
22
ostd/src/arch/riscv/qemu.rs
Normal file
22
ostd/src/arch/riscv/qemu.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Providing the ability to exit QEMU and return a value as debug result.
|
||||||
|
|
||||||
|
/// The exit code of QEMU.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum QemuExitCode {
|
||||||
|
/// The code that indicates a successful exit.
|
||||||
|
Success,
|
||||||
|
/// The code that indicates a failed exit.
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exit QEMU with the given exit code.
|
||||||
|
pub fn exit_qemu(exit_code: QemuExitCode) -> ! {
|
||||||
|
log::debug!("exit qemu with exit code {exit_code:?}");
|
||||||
|
match exit_code {
|
||||||
|
QemuExitCode::Success => sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason),
|
||||||
|
QemuExitCode::Failed => sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::SystemFailure),
|
||||||
|
};
|
||||||
|
unreachable!("qemu does not exit");
|
||||||
|
}
|
39
ostd/src/arch/riscv/serial.rs
Normal file
39
ostd/src/arch/riscv/serial.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The console I/O.
|
||||||
|
|
||||||
|
use alloc::fmt;
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
/// Prints the formatted arguments to the standard output using the serial port.
|
||||||
|
#[inline]
|
||||||
|
pub fn print(args: fmt::Arguments) {
|
||||||
|
Stdout.write_fmt(args).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The callback function for console input.
|
||||||
|
pub type InputCallback = dyn Fn(u8) + Send + Sync + 'static;
|
||||||
|
|
||||||
|
/// Registers a callback function to be called when there is console input.
|
||||||
|
pub fn register_console_input_callback(_f: &'static InputCallback) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Stdout;
|
||||||
|
|
||||||
|
impl Write for Stdout {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
for &c in s.as_bytes() {
|
||||||
|
send(c);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes the serial port.
|
||||||
|
pub(crate) fn init() {}
|
||||||
|
|
||||||
|
/// Sends a byte on the serial port.
|
||||||
|
pub fn send(data: u8) {
|
||||||
|
sbi_rt::console_write_byte(data);
|
||||||
|
}
|
110
ostd/src/arch/riscv/task/mod.rs
Normal file
110
ostd/src/arch/riscv/task/mod.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The architecture support of context switch.
|
||||||
|
|
||||||
|
use crate::task::TaskContextApi;
|
||||||
|
|
||||||
|
core::arch::global_asm!(include_str!("switch.S"));
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct TaskContext {
|
||||||
|
pub regs: CalleeRegs,
|
||||||
|
pub pc: usize,
|
||||||
|
pub fsbase: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Callee-saved registers.
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CalleeRegs {
|
||||||
|
/// sp
|
||||||
|
pub sp: u64,
|
||||||
|
/// s0
|
||||||
|
pub s0: u64,
|
||||||
|
/// s1
|
||||||
|
pub s1: u64,
|
||||||
|
/// s2
|
||||||
|
pub s2: u64,
|
||||||
|
/// s3
|
||||||
|
pub s3: u64,
|
||||||
|
/// s4
|
||||||
|
pub s4: u64,
|
||||||
|
/// s5
|
||||||
|
pub s5: u64,
|
||||||
|
/// s6
|
||||||
|
pub s6: u64,
|
||||||
|
/// s7
|
||||||
|
pub s7: u64,
|
||||||
|
/// s8
|
||||||
|
pub s8: u64,
|
||||||
|
/// s9
|
||||||
|
pub s9: u64,
|
||||||
|
/// s10
|
||||||
|
pub s10: u64,
|
||||||
|
/// s11
|
||||||
|
pub s11: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalleeRegs {
|
||||||
|
/// Creates new `CalleeRegs`
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
CalleeRegs {
|
||||||
|
sp: 0,
|
||||||
|
s0: 0,
|
||||||
|
s1: 0,
|
||||||
|
s2: 0,
|
||||||
|
s3: 0,
|
||||||
|
s4: 0,
|
||||||
|
s5: 0,
|
||||||
|
s6: 0,
|
||||||
|
s7: 0,
|
||||||
|
s8: 0,
|
||||||
|
s9: 0,
|
||||||
|
s10: 0,
|
||||||
|
s11: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskContext {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
TaskContext {
|
||||||
|
regs: CalleeRegs::new(),
|
||||||
|
pc: 0,
|
||||||
|
fsbase: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets thread-local storage pointer.
|
||||||
|
pub fn set_tls_pointer(&mut self, tls: usize) {
|
||||||
|
self.fsbase = tls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets thread-local storage pointer.
|
||||||
|
pub fn tls_pointer(&self) -> usize {
|
||||||
|
self.fsbase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskContextApi for TaskContext {
|
||||||
|
fn set_instruction_pointer(&mut self, ip: usize) {
|
||||||
|
self.pc = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instruction_pointer(&self) -> usize {
|
||||||
|
self.pc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack_pointer(&mut self, sp: usize) {
|
||||||
|
self.regs.sp = sp as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_pointer(&self) -> usize {
|
||||||
|
self.regs.sp as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub(crate) fn context_switch(cur: *mut TaskContext, nxt: *const TaskContext);
|
||||||
|
}
|
37
ostd/src/arch/riscv/task/switch.S
Normal file
37
ostd/src/arch/riscv/task/switch.S
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* SPDX-License-Identifier: MPL-2.0 */
|
||||||
|
|
||||||
|
.text
|
||||||
|
.global context_switch
|
||||||
|
context_switch: # (cur: *mut TaskContext, nxt: *TaskContext)
|
||||||
|
# Save cur's register
|
||||||
|
sd ra, 0x68(a0) # return address
|
||||||
|
sd sp, 0x0(a0)
|
||||||
|
sd s0, 0x8(a0)
|
||||||
|
sd s1, 0x10(a0)
|
||||||
|
sd s2, 0x18(a0)
|
||||||
|
sd s3, 0x20(a0)
|
||||||
|
sd s4, 0x28(a0)
|
||||||
|
sd s5, 0x30(a0)
|
||||||
|
sd s6, 0x38(a0)
|
||||||
|
sd s7, 0x40(a0)
|
||||||
|
sd s8, 0x48(a0)
|
||||||
|
sd s9, 0x50(a0)
|
||||||
|
sd s10, 0x58(a0)
|
||||||
|
sd s11, 0x60(a0)
|
||||||
|
|
||||||
|
# Restore nxt's registers
|
||||||
|
ld ra, 0x68(a1) # return address
|
||||||
|
ld sp, 0x0(a1)
|
||||||
|
ld s0, 0x8(a1)
|
||||||
|
ld s1, 0x10(a1)
|
||||||
|
ld s2, 0x18(a1)
|
||||||
|
ld s3, 0x20(a1)
|
||||||
|
ld s4, 0x28(a1)
|
||||||
|
ld s5, 0x30(a1)
|
||||||
|
ld s6, 0x38(a1)
|
||||||
|
ld s7, 0x40(a1)
|
||||||
|
ld s8, 0x48(a1)
|
||||||
|
ld s9, 0x50(a1)
|
||||||
|
ld s10, 0x58(a1)
|
||||||
|
ld s11, 0x60(a1)
|
||||||
|
ret
|
47
ostd/src/arch/riscv/timer/mod.rs
Normal file
47
ostd/src/arch/riscv/timer/mod.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! The timer support.
|
||||||
|
|
||||||
|
use core::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
use crate::{arch::boot::DEVICE_TREE, io_mem::IoMem};
|
||||||
|
|
||||||
|
/// The timer frequency (Hz). Here we choose 1000Hz since 1000Hz is easier for unit conversion and
|
||||||
|
/// convenient for timer. What's more, the frequency cannot be set too high or too low, 1000Hz is
|
||||||
|
/// a modest choice.
|
||||||
|
///
|
||||||
|
/// For system performance reasons, this rate cannot be set too high, otherwise most of the time
|
||||||
|
/// is spent executing timer code.
|
||||||
|
pub const TIMER_FREQ: u64 = 1000;
|
||||||
|
|
||||||
|
pub(crate) static TIMEBASE_FREQ: AtomicU64 = AtomicU64::new(1);
|
||||||
|
|
||||||
|
/// [`IoMem`] of goldfish RTC, which will be used by `aster-time`.
|
||||||
|
pub static GOLDFISH_IO_MEM: Once<IoMem> = Once::new();
|
||||||
|
|
||||||
|
pub(super) fn init() {
|
||||||
|
let timer_freq = DEVICE_TREE
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.cpus()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.timebase_frequency() as u64;
|
||||||
|
TIMEBASE_FREQ.store(timer_freq, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let chosen = DEVICE_TREE.get().unwrap().find_node("/soc/rtc").unwrap();
|
||||||
|
if let Some(compatible) = chosen.compatible()
|
||||||
|
&& compatible.all().any(|c| c == "google,goldfish-rtc")
|
||||||
|
{
|
||||||
|
let region = chosen.reg().unwrap().next().unwrap();
|
||||||
|
let io_mem = unsafe {
|
||||||
|
IoMem::new(
|
||||||
|
(region.starting_address as usize)
|
||||||
|
..(region.starting_address as usize) + region.size.unwrap(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
GOLDFISH_IO_MEM.call_once(|| io_mem);
|
||||||
|
}
|
||||||
|
}
|
45
ostd/src/arch/riscv/trap/mod.rs
Normal file
45
ostd/src/arch/riscv/trap/mod.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
//! Handles trap.
|
||||||
|
|
||||||
|
mod trap;
|
||||||
|
|
||||||
|
pub use trap::{GeneralRegs, TrapFrame, UserContext};
|
||||||
|
|
||||||
|
use crate::cpu_local_cell;
|
||||||
|
|
||||||
|
cpu_local_cell! {
|
||||||
|
static IS_KERNEL_INTERRUPTED: bool = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize interrupt handling on RISC-V.
|
||||||
|
pub unsafe fn init(on_bsp: bool) {
|
||||||
|
self::trap::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this function is called within the context of an IRQ handler
|
||||||
|
/// and the IRQ occurs while the CPU is executing in the kernel mode.
|
||||||
|
/// Otherwise, it returns false.
|
||||||
|
pub fn is_kernel_interrupted() -> bool {
|
||||||
|
IS_KERNEL_INTERRUPTED.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle traps (only from kernel).
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn trap_handler(f: &mut TrapFrame) {
|
||||||
|
use riscv::register::scause::Trap;
|
||||||
|
|
||||||
|
match riscv::register::scause::read().cause() {
|
||||||
|
Trap::Interrupt(_) => {
|
||||||
|
IS_KERNEL_INTERRUPTED.store(true);
|
||||||
|
todo!();
|
||||||
|
IS_KERNEL_INTERRUPTED.store(false);
|
||||||
|
}
|
||||||
|
Trap::Exception(e) => {
|
||||||
|
let stval = riscv::register::stval::read();
|
||||||
|
panic!(
|
||||||
|
"Cannot handle kernel cpu exception: {e:?}. stval: {stval:#x}, trapframe: {f:#x?}.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
ostd/src/arch/riscv/trap/trap.S
Normal file
176
ostd/src/arch/riscv/trap/trap.S
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/* SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
*
|
||||||
|
* The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
* which is released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
*
|
||||||
|
* We make the following new changes:
|
||||||
|
* * Add the `trap_handler_table`.
|
||||||
|
*
|
||||||
|
* These changes are released under the following license:
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
# Constants / Macros defined in Rust code:
|
||||||
|
# XLENB
|
||||||
|
# LOAD
|
||||||
|
# STORE
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.global trap_entry
|
||||||
|
.balign 4
|
||||||
|
trap_entry:
|
||||||
|
# If coming from userspace, preserve the user stack pointer and load
|
||||||
|
# the kernel stack pointer. If we came from the kernel, sscratch
|
||||||
|
# will contain 0, and we should continue on the current stack.
|
||||||
|
csrrw sp, sscratch, sp
|
||||||
|
bnez sp, trap_from_user
|
||||||
|
trap_from_kernel:
|
||||||
|
csrr sp, sscratch
|
||||||
|
addi sp, sp, -34 * XLENB
|
||||||
|
# sscratch = previous-sp, sp = kernel-sp
|
||||||
|
trap_from_user:
|
||||||
|
# save general registers except sp(x2)
|
||||||
|
STORE_SP x1, 1
|
||||||
|
STORE_SP x3, 3
|
||||||
|
STORE_SP x4, 4
|
||||||
|
STORE_SP x5, 5
|
||||||
|
STORE_SP x6, 6
|
||||||
|
STORE_SP x7, 7
|
||||||
|
STORE_SP x8, 8
|
||||||
|
STORE_SP x9, 9
|
||||||
|
STORE_SP x10, 10
|
||||||
|
STORE_SP x11, 11
|
||||||
|
STORE_SP x12, 12
|
||||||
|
STORE_SP x13, 13
|
||||||
|
STORE_SP x14, 14
|
||||||
|
STORE_SP x15, 15
|
||||||
|
STORE_SP x16, 16
|
||||||
|
STORE_SP x17, 17
|
||||||
|
STORE_SP x18, 18
|
||||||
|
STORE_SP x19, 19
|
||||||
|
STORE_SP x20, 20
|
||||||
|
STORE_SP x21, 21
|
||||||
|
STORE_SP x22, 22
|
||||||
|
STORE_SP x23, 23
|
||||||
|
STORE_SP x24, 24
|
||||||
|
STORE_SP x25, 25
|
||||||
|
STORE_SP x26, 26
|
||||||
|
STORE_SP x27, 27
|
||||||
|
STORE_SP x28, 28
|
||||||
|
STORE_SP x29, 29
|
||||||
|
STORE_SP x30, 30
|
||||||
|
STORE_SP x31, 31
|
||||||
|
|
||||||
|
# save sp, sstatus, sepc
|
||||||
|
csrrw t0, sscratch, x0 # sscratch = 0 (kernel)
|
||||||
|
csrr t1, sstatus
|
||||||
|
csrr t2, sepc
|
||||||
|
STORE_SP t0, 2 # save sp
|
||||||
|
STORE_SP t1, 32 # save sstatus
|
||||||
|
STORE_SP t2, 33 # save sepc
|
||||||
|
|
||||||
|
li t0, 3 << 13
|
||||||
|
or t1, t1, t0 # sstatus.FS = Dirty (3)
|
||||||
|
csrw sstatus, t1
|
||||||
|
|
||||||
|
andi t1, t1, 1 << 8 # sstatus.SPP == 1
|
||||||
|
beqz t1, end_trap_from_user
|
||||||
|
end_trap_from_kernel:
|
||||||
|
mv a0, sp # first arg is TrapFrame
|
||||||
|
la ra, trap_return # set return address
|
||||||
|
j trap_handler
|
||||||
|
|
||||||
|
end_trap_from_user:
|
||||||
|
# load callee-saved registers
|
||||||
|
LOAD_SP sp, 0
|
||||||
|
LOAD_SP s0, 0
|
||||||
|
LOAD_SP s1, 1
|
||||||
|
LOAD_SP s2, 2
|
||||||
|
LOAD_SP s3, 3
|
||||||
|
LOAD_SP s4, 4
|
||||||
|
LOAD_SP s5, 5
|
||||||
|
LOAD_SP s6, 6
|
||||||
|
LOAD_SP s7, 7
|
||||||
|
LOAD_SP s8, 8
|
||||||
|
LOAD_SP s9, 9
|
||||||
|
LOAD_SP s10, 10
|
||||||
|
LOAD_SP s11, 11
|
||||||
|
LOAD_SP ra, 12
|
||||||
|
# not callee-saved, but is used to store mhartid
|
||||||
|
LOAD_SP gp, 13
|
||||||
|
addi sp, sp, 14 * XLENB
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global run_user
|
||||||
|
run_user:
|
||||||
|
# save callee-saved registers
|
||||||
|
addi sp, sp, -14 * XLENB
|
||||||
|
STORE_SP s0, 0
|
||||||
|
STORE_SP s1, 1
|
||||||
|
STORE_SP s2, 2
|
||||||
|
STORE_SP s3, 3
|
||||||
|
STORE_SP s4, 4
|
||||||
|
STORE_SP s5, 5
|
||||||
|
STORE_SP s6, 6
|
||||||
|
STORE_SP s7, 7
|
||||||
|
STORE_SP s8, 8
|
||||||
|
STORE_SP s9, 9
|
||||||
|
STORE_SP s10, 10
|
||||||
|
STORE_SP s11, 11
|
||||||
|
STORE_SP ra, 12
|
||||||
|
# not callee-saved, but is used to store mhartid
|
||||||
|
STORE_SP gp, 13
|
||||||
|
|
||||||
|
mv t0, sp
|
||||||
|
mv sp, a0
|
||||||
|
STORE_SP t0, 0 # save kernel-sp
|
||||||
|
csrw sscratch, sp # sscratch = bottom of trap frame
|
||||||
|
|
||||||
|
trap_return:
|
||||||
|
LOAD_SP t0, 32 # t0 = sstatus
|
||||||
|
LOAD_SP t1, 33 # t1 = sepc
|
||||||
|
csrw sstatus, t0 # load sstatus
|
||||||
|
csrw sepc, t1 # load sepc
|
||||||
|
|
||||||
|
# restore general registers except sp(x2)
|
||||||
|
LOAD_SP x1, 1
|
||||||
|
LOAD_SP x3, 3
|
||||||
|
LOAD_SP x4, 4
|
||||||
|
LOAD_SP x5, 5
|
||||||
|
LOAD_SP x6, 6
|
||||||
|
LOAD_SP x7, 7
|
||||||
|
LOAD_SP x8, 8
|
||||||
|
LOAD_SP x9, 9
|
||||||
|
LOAD_SP x10, 10
|
||||||
|
LOAD_SP x11, 11
|
||||||
|
LOAD_SP x12, 12
|
||||||
|
LOAD_SP x13, 13
|
||||||
|
LOAD_SP x14, 14
|
||||||
|
LOAD_SP x15, 15
|
||||||
|
LOAD_SP x16, 16
|
||||||
|
LOAD_SP x17, 17
|
||||||
|
LOAD_SP x18, 18
|
||||||
|
LOAD_SP x19, 19
|
||||||
|
LOAD_SP x20, 20
|
||||||
|
LOAD_SP x21, 21
|
||||||
|
LOAD_SP x22, 22
|
||||||
|
LOAD_SP x23, 23
|
||||||
|
LOAD_SP x24, 24
|
||||||
|
LOAD_SP x25, 25
|
||||||
|
LOAD_SP x26, 26
|
||||||
|
LOAD_SP x27, 27
|
||||||
|
LOAD_SP x28, 28
|
||||||
|
LOAD_SP x29, 29
|
||||||
|
LOAD_SP x30, 30
|
||||||
|
LOAD_SP x31, 31
|
||||||
|
# restore sp last
|
||||||
|
LOAD_SP x2, 2
|
||||||
|
|
||||||
|
# return from supervisor call
|
||||||
|
sret
|
221
ostd/src/arch/riscv/trap/trap.rs
Normal file
221
ostd/src/arch/riscv/trap/trap.rs
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0 OR MIT
|
||||||
|
//
|
||||||
|
// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs),
|
||||||
|
// which is released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 - 2024 Runji Wang
|
||||||
|
//
|
||||||
|
// We make the following new changes:
|
||||||
|
// * Implement the `trap_handler` of Asterinas.
|
||||||
|
//
|
||||||
|
// These changes are released under the following license:
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use core::arch::{asm, global_asm};
|
||||||
|
|
||||||
|
use crate::Pod;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
global_asm!(
|
||||||
|
r"
|
||||||
|
.equ XLENB, 4
|
||||||
|
.macro LOAD_SP a1, a2
|
||||||
|
lw \a1, \a2*XLENB(sp)
|
||||||
|
.endm
|
||||||
|
.macro STORE_SP a1, a2
|
||||||
|
sw \a1, \a2*XLENB(sp)
|
||||||
|
.endm
|
||||||
|
"
|
||||||
|
);
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
global_asm!(
|
||||||
|
r"
|
||||||
|
.equ XLENB, 8
|
||||||
|
.macro LOAD_SP a1, a2
|
||||||
|
ld \a1, \a2*XLENB(sp)
|
||||||
|
.endm
|
||||||
|
.macro STORE_SP a1, a2
|
||||||
|
sd \a1, \a2*XLENB(sp)
|
||||||
|
.endm
|
||||||
|
"
|
||||||
|
);
|
||||||
|
|
||||||
|
global_asm!(include_str!("trap.S"));
|
||||||
|
|
||||||
|
/// Initialize interrupt handling for the current HART.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// This function will:
|
||||||
|
/// - Set `sscratch` to 0.
|
||||||
|
/// - Set `stvec` to internal exception vector.
|
||||||
|
///
|
||||||
|
/// You **MUST NOT** modify these registers later.
|
||||||
|
pub unsafe fn init() {
|
||||||
|
// Set sscratch register to 0, indicating to exception vector that we are
|
||||||
|
// presently executing in the kernel
|
||||||
|
asm!("csrw sscratch, zero");
|
||||||
|
// Set the exception vector address
|
||||||
|
asm!("csrw stvec, {}", in(reg) trap_entry as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trap frame of kernel interrupt
|
||||||
|
///
|
||||||
|
/// # Trap handler
|
||||||
|
///
|
||||||
|
/// You need to define a handler function like this:
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// #[no_mangle]
|
||||||
|
/// pub extern "C" fn trap_handler(tf: &mut TrapFrame) {
|
||||||
|
/// println!("TRAP! tf: {:#x?}", tf);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct TrapFrame {
|
||||||
|
/// General registers
|
||||||
|
pub general: GeneralRegs,
|
||||||
|
/// Supervisor Status
|
||||||
|
pub sstatus: usize,
|
||||||
|
/// Supervisor Exception Program Counter
|
||||||
|
pub sepc: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Saved registers on a trap.
|
||||||
|
#[derive(Debug, Default, Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct UserContext {
|
||||||
|
/// General registers
|
||||||
|
pub general: GeneralRegs,
|
||||||
|
/// Supervisor Status
|
||||||
|
pub sstatus: usize,
|
||||||
|
/// Supervisor Exception Program Counter
|
||||||
|
pub sepc: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContext {
|
||||||
|
/// Go to user space with the context, and come back when a trap occurs.
|
||||||
|
///
|
||||||
|
/// On return, the context will be reset to the status before the trap.
|
||||||
|
/// Trap reason and error code will be returned.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// use trapframe::{UserContext, GeneralRegs};
|
||||||
|
///
|
||||||
|
/// // init user space context
|
||||||
|
/// let mut context = UserContext {
|
||||||
|
/// general: GeneralRegs {
|
||||||
|
/// sp: 0x10000,
|
||||||
|
/// ..Default::default()
|
||||||
|
/// },
|
||||||
|
/// sepc: 0x1000,
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
|
/// // go to user
|
||||||
|
/// context.run();
|
||||||
|
/// // back from user
|
||||||
|
/// println!("back from user: {:#x?}", context);
|
||||||
|
/// ```
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
unsafe { run_user(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// General registers
|
||||||
|
#[derive(Debug, Default, Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct GeneralRegs {
|
||||||
|
pub zero: usize,
|
||||||
|
pub ra: usize,
|
||||||
|
pub sp: usize,
|
||||||
|
pub gp: usize,
|
||||||
|
pub tp: usize,
|
||||||
|
pub t0: usize,
|
||||||
|
pub t1: usize,
|
||||||
|
pub t2: usize,
|
||||||
|
pub s0: usize,
|
||||||
|
pub s1: usize,
|
||||||
|
pub a0: usize,
|
||||||
|
pub a1: usize,
|
||||||
|
pub a2: usize,
|
||||||
|
pub a3: usize,
|
||||||
|
pub a4: usize,
|
||||||
|
pub a5: usize,
|
||||||
|
pub a6: usize,
|
||||||
|
pub a7: usize,
|
||||||
|
pub s2: usize,
|
||||||
|
pub s3: usize,
|
||||||
|
pub s4: usize,
|
||||||
|
pub s5: usize,
|
||||||
|
pub s6: usize,
|
||||||
|
pub s7: usize,
|
||||||
|
pub s8: usize,
|
||||||
|
pub s9: usize,
|
||||||
|
pub s10: usize,
|
||||||
|
pub s11: usize,
|
||||||
|
pub t3: usize,
|
||||||
|
pub t4: usize,
|
||||||
|
pub t5: usize,
|
||||||
|
pub t6: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserContext {
|
||||||
|
/// Get number of syscall
|
||||||
|
pub fn get_syscall_num(&self) -> usize {
|
||||||
|
self.general.a7
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get return value of syscall
|
||||||
|
pub fn get_syscall_ret(&self) -> usize {
|
||||||
|
self.general.a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set return value of syscall
|
||||||
|
pub fn set_syscall_ret(&mut self, ret: usize) {
|
||||||
|
self.general.a0 = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get syscall args
|
||||||
|
pub fn get_syscall_args(&self) -> [usize; 6] {
|
||||||
|
[
|
||||||
|
self.general.a0,
|
||||||
|
self.general.a1,
|
||||||
|
self.general.a2,
|
||||||
|
self.general.a3,
|
||||||
|
self.general.a4,
|
||||||
|
self.general.a5,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set instruction pointer
|
||||||
|
pub fn set_ip(&mut self, ip: usize) {
|
||||||
|
self.sepc = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set stack pointer
|
||||||
|
pub fn set_sp(&mut self, sp: usize) {
|
||||||
|
self.general.sp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get stack pointer
|
||||||
|
pub fn get_sp(&self) -> usize {
|
||||||
|
self.general.sp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set tls pointer
|
||||||
|
pub fn set_tls(&mut self, tls: usize) {
|
||||||
|
self.general.gp = tls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(improper_ctypes)]
|
||||||
|
extern "C" {
|
||||||
|
fn trap_entry();
|
||||||
|
fn run_user(regs: &mut UserContext);
|
||||||
|
}
|
@ -39,7 +39,7 @@ use kernel::apic::ioapic;
|
|||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
|
||||||
#[cfg(feature = "cvm_guest")]
|
#[cfg(feature = "cvm_guest")]
|
||||||
pub(crate) fn check_tdx_init() {
|
pub(crate) fn init_cvm_guest() {
|
||||||
match init_tdx() {
|
match init_tdx() {
|
||||||
Ok(td_info) => {
|
Ok(td_info) => {
|
||||||
early_println!(
|
early_println!(
|
||||||
|
@ -15,8 +15,7 @@ use log::debug;
|
|||||||
|
|
||||||
use self::bus::MmioBus;
|
use self::bus::MmioBus;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::kernel::IO_APIC, bus::mmio::common_device::MmioCommonDevice, mm::paddr_to_vaddr,
|
bus::mmio::common_device::MmioCommonDevice, mm::paddr_to_vaddr, sync::SpinLock, trap::IrqLine,
|
||||||
sync::SpinLock, trap::IrqLine,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
@ -45,14 +44,16 @@ pub(crate) fn init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: The address 0xFEB0_0000 is obtained from an instance of microvm, and it may not work in other architecture.
|
// FIXME: The address 0xFEB0_0000 is obtained from an instance of microvm, and it may not work in other architecture.
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
iter_range(0xFEB0_0000..0xFEB0_4000);
|
iter_range(0xFEB0_0000..0xFEB0_4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn iter_range(range: Range<usize>) {
|
fn iter_range(range: Range<usize>) {
|
||||||
debug!("[Virtio]: Iter MMIO range:{:x?}", range);
|
debug!("[Virtio]: Iter MMIO range:{:x?}", range);
|
||||||
let mut current = range.end;
|
let mut current = range.end;
|
||||||
let mut lock = MMIO_BUS.lock();
|
let mut lock = MMIO_BUS.lock();
|
||||||
let io_apics = IO_APIC.get().unwrap();
|
let io_apics = crate::arch::kernel::IO_APIC.get().unwrap();
|
||||||
let is_ioapic2 = io_apics.len() == 2;
|
let is_ioapic2 = io_apics.len() == 2;
|
||||||
let mut io_apic = if is_ioapic2 {
|
let mut io_apic = if is_ioapic2 {
|
||||||
io_apics.get(1).unwrap().lock()
|
io_apics.get(1).unwrap().lock()
|
||||||
|
@ -16,6 +16,8 @@ pub enum BusProbeError {
|
|||||||
|
|
||||||
/// Initializes the bus
|
/// Initializes the bus
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
pci::init();
|
pci::init();
|
||||||
|
|
||||||
mmio::init();
|
mmio::init();
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
pub mod local;
|
pub mod local;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(target_arch = "x86_64")]{
|
if #[cfg(target_arch = "x86_64")] {
|
||||||
pub use crate::arch::x86::cpu::*;
|
pub use crate::arch::x86::cpu::*;
|
||||||
|
} else if #[cfg(target_arch = "riscv64")] {
|
||||||
|
pub use crate::arch::riscv::cpu::*;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ pub unsafe fn init() {
|
|||||||
arch::serial::init();
|
arch::serial::init();
|
||||||
|
|
||||||
#[cfg(feature = "cvm_guest")]
|
#[cfg(feature = "cvm_guest")]
|
||||||
arch::check_tdx_init();
|
arch::init_cvm_guest();
|
||||||
|
|
||||||
// SAFETY: This function is called only once and only on the BSP.
|
// SAFETY: This function is called only once and only on the BSP.
|
||||||
unsafe { cpu::local::early_init_bsp_local_base() };
|
unsafe { cpu::local::early_init_bsp_local_base() };
|
||||||
|
@ -943,3 +943,10 @@ const fn is_pod_once<T: Pod>() -> bool {
|
|||||||
|
|
||||||
size == 1 || size == 2 || size == 4 || size == 8
|
size == 1 || size == 2 || size == 4 || size == 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
const fn is_pod_once<T: Pod>() -> bool {
|
||||||
|
let size = size_of::<T>();
|
||||||
|
|
||||||
|
size == 1 || size == 2 || size == 4 || size == 8
|
||||||
|
}
|
||||||
|
@ -80,7 +80,10 @@ pub fn kernel_loaded_offset() -> usize {
|
|||||||
KERNEL_CODE_BASE_VADDR
|
KERNEL_CODE_BASE_VADDR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_8000_0000 << ADDR_WIDTH_SHIFT;
|
const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_8000_0000 << ADDR_WIDTH_SHIFT;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
const KERNEL_CODE_BASE_VADDR: usize = 0xffff_ffff_0000_0000 << ADDR_WIDTH_SHIFT;
|
||||||
|
|
||||||
const FRAME_METADATA_CAP_VADDR: Vaddr = 0xffff_ff00_0000_0000 << ADDR_WIDTH_SHIFT;
|
const FRAME_METADATA_CAP_VADDR: Vaddr = 0xffff_ff00_0000_0000 << ADDR_WIDTH_SHIFT;
|
||||||
const FRAME_METADATA_BASE_VADDR: Vaddr = 0xffff_fe00_0000_0000 << ADDR_WIDTH_SHIFT;
|
const FRAME_METADATA_BASE_VADDR: Vaddr = 0xffff_fe00_0000_0000 << ADDR_WIDTH_SHIFT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user