diff --git a/crate/process/src/interrupt.rs b/crate/process/src/interrupt.rs index c33be0c..8bb4d00 100644 --- a/crate/process/src/interrupt.rs +++ b/crate/process/src/interrupt.rs @@ -28,6 +28,20 @@ pub unsafe fn disable_and_store() -> usize { } } +#[inline(always)] +#[cfg(target_arch = "riscv64")] +pub unsafe fn disable_and_store() -> usize { + if option_env!("m_mode").is_some() { + let mstatus: usize; + asm!("csrrci $0, 0x300, 1 << 3" : "=r"(mstatus)); + mstatus & (1 << 3) + } else { + let sstatus: usize; + asm!("csrrci $0, 0x100, 1 << 1" : "=r"(sstatus)); + sstatus & (1 << 1) + } +} + #[inline(always)] #[cfg(target_arch = "riscv32")] pub unsafe fn restore(flags: usize) { @@ -38,6 +52,16 @@ pub unsafe fn restore(flags: usize) { } } +#[inline(always)] +#[cfg(target_arch = "riscv64")] +pub unsafe fn restore(flags: usize) { + if option_env!("m_mode").is_some() { + asm!("csrs 0x300, $0" :: "r"(flags)); + } else { + asm!("csrs 0x100, $0" :: "r"(flags)); + } +} + #[inline(always)] #[cfg(target_arch = "aarch64")] pub unsafe fn disable_and_store() -> usize { diff --git a/kernel/run-qemu-script b/kernel/run-qemu-script index 75e2b3d..133055f 100755 --- a/kernel/run-qemu-script +++ b/kernel/run-qemu-script @@ -185,7 +185,6 @@ rustc --crate-name bbl /home/dzy/rust/RustOS/crate/bbl/src/lib.rs \ -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ -L $PWD/outdir @@ -250,7 +249,6 @@ rustc --crate-name bit_allocator /home/dzy/rust/RustOS/crate/bit-allocator/src/l -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ -L $PWD/outdir \ @@ -277,7 +275,6 @@ rustc --edition=2018 --crate-name ucore_process /home/dzy/rust/RustOS/crate/proc -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ --extern log=$PWD/outdir/liblog.rlib \ --extern spin=$PWD/outdir/libspin.rlib \ -L $PWD/outdir @@ -292,7 +289,6 @@ rustc --edition=2018 --crate-name ucore_memory /home/dzy/rust/RustOS/crate/memor -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ --extern log=$PWD/outdir/liblog.rlib \ -L $PWD/outdir @@ -358,7 +354,6 @@ rustc --edition=2018 --crate-name ucore src/lib.rs \ -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ -L $PWD/outdir \ --extern bbl=$PWD/outdir/libbbl.rlib \ --extern bit_allocator=$PWD/outdir/libbit_allocator.rlib \ @@ -376,7 +371,7 @@ rustc --edition=2018 --crate-name ucore src/lib.rs \ --extern volatile=$PWD/outdir/libvolatile.rlib \ --extern xmas_elf=$PWD/outdir/libxmas_elf.rlib \ -L native=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/build/ucore-6787973a04115b52/out \ - -L native=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/build/ucore-6787973a04115b52/out -l static=atomic_rt -l static=sfsimg + -l static=atomic_rt -l static=sfsimg @@ -387,7 +382,6 @@ rustc --edition=2018 --crate-name ucore src/main.rs \ -C debug-assertions=on \ --out-dir $PWD/outdir \ --target /home/dzy/rust/RustOS/kernel/riscv32-blog_os.json \ - -C incremental=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/incremental \ -L $PWD/outdir \ --extern bbl=$PWD/outdir/libbbl.rlib \ --extern bit_allocator=$PWD/outdir/libbit_allocator.rlib \ @@ -405,7 +399,6 @@ rustc --edition=2018 --crate-name ucore src/main.rs \ --extern ucore_process=$PWD/outdir/libucore_process.rlib \ --extern volatile=$PWD/outdir/libvolatile.rlib \ --extern xmas_elf=$PWD/outdir/libxmas_elf.rlib \ - -L native=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/build/ucore-6787973a04115b52/out \ -L native=/home/dzy/rust/RustOS/kernel/target/riscv32-blog_os/debug/build/ucore-6787973a04115b52/out @@ -419,7 +412,7 @@ cd ../riscv-pk && mkdir -p build && cd build --host=riscv32-unknown-elf \ --with-payload=../../kernel/outdir/ucore -make +make -j8 cp bbl ../../kernel/outdir/kernel.bin diff --git a/kernel/run-qemu-script-custom-llc b/kernel/run-qemu-script-custom-llc new file mode 100755 index 0000000..cdb58f1 --- /dev/null +++ b/kernel/run-qemu-script-custom-llc @@ -0,0 +1,449 @@ +#!/bin/bash +set -e + +# The contents are adopted from xbuild verbose output. +if ! [ -d outdir ] +then + echo "You have to \`mkdir outdir\` first." + echo "If you know what you're doing, do this yourself, otherwise quit." + exit 1 +fi + +#export LLC=~dzy/rust/rust/build/x86_64-unknown-linux-gnu/llvm/bin/llc +export LLC=~dzy/llvm/rust-llvm-build/bin/llc + +gen_full_rlib() { + cd outdir + for X in ${CNAME}.*ll + do + sed 's/, retainedNodes: ![0-9]\+//' -i ${X} + $LLC -march=riscv64 -filetype=obj ${X} + done + for X in ${CNAME}.*o + do + ar r lib${CNAME}.rlib ${X} + done + cd .. +} + + +#CNAME=core +#rustc --crate-name ${CNAME} /home/dzy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=3 \ +# -C debuginfo=2 \ +# -Z force-unstable-if-unmarked \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json +#gen_full_rlib +# +#CNAME=compiler_builtins +## omit build_script_build +#rustc --crate-name compiler_builtins /home/dzy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcompiler_builtins/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=3 \ +# -C debuginfo=2 \ +# -Z force-unstable-if-unmarked \ +# --cfg 'feature="compiler-builtins"' \ +# --cfg 'feature="mem"' \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir +#gen_full_rlib +# +#CNAME=alloc +#rustc --crate-name alloc /home/dzy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=3 \ +# -C debuginfo=2 \ +# -Z force-unstable-if-unmarked \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir +#gen_full_rlib +# +# +# +#CNAME=semver_parser +#rustc --crate-name semver_parser /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/semver-parser-0.7.0/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=cfg_if +#rustc --crate-name cfg_if /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-0.1.6/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=spin +#rustc --crate-name spin /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.4.10/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --cfg 'feature="const_fn"' \ +# --cfg 'feature="default"' \ +# --cfg 'feature="once"' \ +# --cfg 'feature="unstable"' \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=cc +#rustc --crate-name cc /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.25/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=static_assertions +#rustc --crate-name static_assertions /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/static_assertions-0.3.1/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bit_field +#rustc --crate-name bit_field /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/bit_field-0.9.0/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=zero +#rustc --crate-name zero /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/zero-0.1.2/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bit_vec +#rustc --crate-name bit_vec /home/dzy/.cargo/git/checkouts/bit-vec-437fa4a002bd318d/9861a58d6e76/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bitflags +#rustc --crate-name bitflags /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.0.4/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --cfg 'feature="default"' \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=volatile +#rustc --crate-name volatile /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/volatile-0.2.5/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=once +#rustc --crate-name once /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/once-0.3.3/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bbl +#rustc --crate-name bbl /home/dzy/rust/RustOS/crate/bbl/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir +#gen_full_rlib +# +#CNAME=log +#rustc --crate-name log /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.6/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=linked_list_allocator +#rustc --crate-name linked_list_allocator /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/linked_list_allocator-0.6.3/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --cfg 'feature="default"' \ +# --cfg 'feature="spin"' \ +# --cfg 'feature="use_spin"' \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=lazy_static +#rustc --crate-name lazy_static /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.2.0/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --cfg 'feature="spin"' \ +# --cfg 'feature="spin_no_std"' \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=xmas_elf +#rustc --crate-name xmas_elf /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/xmas-elf-0.6.2/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bit_allocator +#rustc --crate-name bit_allocator /home/dzy/rust/RustOS/crate/bit-allocator/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir +#gen_full_rlib +# +# +#CNAME=simple_filesystem +#rustc --edition=2018 --crate-name simple_filesystem /home/dzy/.cargo/git/checkouts/simplefilesystem-rust-868ccb44dbeefdea/249383f7e3f1/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --extern bit_vec=$PWD/outdir/libbit_vec.rlib \ +# --extern spin=$PWD/outdir/libspin.rlib \ +# --extern static_assertions=$PWD/outdir/libstatic_assertions.rlib \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=ucore_process +#rustc --edition=2018 --crate-name ucore_process /home/dzy/rust/RustOS/crate/process/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# --extern log=$PWD/outdir/liblog.rlib \ +# --extern spin=$PWD/outdir/libspin.rlib \ +# -L $PWD/outdir +#gen_full_rlib +# +#CNAME=ucore_memory +#rustc --edition=2018 --crate-name ucore_memory /home/dzy/rust/RustOS/crate/memory/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# --extern log=$PWD/outdir/liblog.rlib \ +# -L $PWD/outdir +#gen_full_rlib +# +#CNAME=semver +#rustc --crate-name semver /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/semver-0.9.0/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --cfg 'feature="default"' \ +# --out-dir $PWD/outdir \ +# -L $PWD/outdir \ +# --extern semver_parser=$PWD/outdir/libsemver_parser.rlib \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=rustc_version +## omit build_script_build +#rustc --crate-name rustc_version /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/rustc_version-0.2.3/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# -L $PWD/outdir \ +# --extern semver=$PWD/outdir/libsemver.rlib \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=bare_metal +## omit build_script_build +#rustc --crate-name bare_metal /home/dzy/.cargo/registry/src/github.com-1ecc6299db9ec823/bare-metal-0.2.4/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --cap-lints allow +#gen_full_rlib +# +#CNAME=riscv +#rustc --crate-name riscv /home/dzy/.cargo/git/checkouts/riscv-1e845b622ce46f1d/966eb26d5e8d/src/lib.rs \ +# --color never --crate-type lib --emit=metadata,llvm-ir \ +# -C opt-level=1 \ +# -C debuginfo=2 \ +# -C debug-assertions=on \ +# --out-dir $PWD/outdir \ +# --target /home/dzy/rust/RustOS/kernel/rv64.json \ +# -L $PWD/outdir \ +# --extern bare_metal=$PWD/outdir/libbare_metal.rlib \ +# --extern bit_field=$PWD/outdir/libbit_field.rlib \ +# --extern bitflags=$PWD/outdir/libbitflags.rlib \ +# --cap-lints allow +#gen_full_rlib +# + +CNAME=ucore +rustc --edition=2018 --crate-name ucore src/lib.rs \ + --color never --crate-type lib --emit=metadata,llvm-ir \ + -C opt-level=1 \ + -C debuginfo=2 \ + -C debug-assertions=on \ + --out-dir $PWD/outdir \ + --target /home/dzy/rust/RustOS/kernel/rv64.json \ + -L $PWD/outdir \ + --extern bbl=$PWD/outdir/libbbl.rlib \ + --extern bit_allocator=$PWD/outdir/libbit_allocator.rlib \ + --extern bit_field=$PWD/outdir/libbit_field.rlib \ + --extern bitflags=$PWD/outdir/libbitflags.rlib \ + --extern lazy_static=$PWD/outdir/liblazy_static.rlib \ + --extern linked_list_allocator=$PWD/outdir/liblinked_list_allocator.rlib \ + --extern log=$PWD/outdir/liblog.rlib \ + --extern once=$PWD/outdir/libonce.rlib \ + --extern riscv=$PWD/outdir/libriscv.rlib \ + --extern simple_filesystem=$PWD/outdir/libsimple_filesystem.rlib \ + --extern spin=$PWD/outdir/libspin.rlib \ + --extern ucore_memory=$PWD/outdir/libucore_memory.rlib \ + --extern ucore_process=$PWD/outdir/libucore_process.rlib \ + --extern volatile=$PWD/outdir/libvolatile.rlib \ + --extern xmas_elf=$PWD/outdir/libxmas_elf.rlib \ + -L native=/home/dzy/rust/RustOS/kernel/target/rv64/debug/build/ucore-6787973a04115b52/out \ + -L native=/home/dzy/rust/RustOS/kernel/target/rv64/debug/build/ucore-6787973a04115b52/out -l static=atomic_rt -l static=sfsimg +gen_full_rlib + +rustc --edition=2018 --crate-name ucore src/main.rs \ + --color never --crate-type bin --emit=metadata,llvm-ir \ + -C opt-level=1 \ + -C debuginfo=2 \ + -C debug-assertions=on \ + --out-dir $PWD/outdir \ + --target /home/dzy/rust/RustOS/kernel/rv64.json \ + -L $PWD/outdir \ + --extern bbl=$PWD/outdir/libbbl.rlib \ + --extern bit_allocator=$PWD/outdir/libbit_allocator.rlib \ + --extern bit_field=$PWD/outdir/libbit_field.rlib \ + --extern bitflags=$PWD/outdir/libbitflags.rlib \ + --extern lazy_static=$PWD/outdir/liblazy_static.rlib \ + --extern linked_list_allocator=$PWD/outdir/liblinked_list_allocator.rlib \ + --extern log=$PWD/outdir/liblog.rlib \ + --extern once=$PWD/outdir/libonce.rlib \ + --extern riscv=$PWD/outdir/libriscv.rlib \ + --extern simple_filesystem=$PWD/outdir/libsimple_filesystem.rlib \ + --extern spin=$PWD/outdir/libspin.rlib \ + --extern ucore=$PWD/outdir/libucore.rlib \ + --extern ucore_memory=$PWD/outdir/libucore_memory.rlib \ + --extern ucore_process=$PWD/outdir/libucore_process.rlib \ + --extern volatile=$PWD/outdir/libvolatile.rlib \ + --extern xmas_elf=$PWD/outdir/libxmas_elf.rlib \ + -L native=/home/dzy/rust/RustOS/kernel/target/rv64/debug/build/ucore-6787973a04115b52/out \ + -L native=/home/dzy/rust/RustOS/kernel/target/rv64/debug/build/ucore-6787973a04115b52/out + +exit 0 + + + + +cd ../riscv-pk && mkdir -p build && cd build + +../configure \ + --with-arch=rv32imac \ + --disable-fp-emulation \ + --host=riscv32-unknown-elf \ + --with-payload=../../kernel/outdir/ucore + +make + +cp bbl ../../kernel/outdir/kernel.bin + +cd ../../kernel + +qemu-system-riscv32 -smp cores=4 -nographic -machine virt -kernel outdir/kernel.bin || [ $? -eq 11 ] # run qemu and assert it exit 11 + + diff --git a/kernel/rv64.json b/kernel/rv64.json new file mode 100644 index 0000000..7aea25e --- /dev/null +++ b/kernel/rv64.json @@ -0,0 +1,36 @@ +{ + "llvm-target": "riscv64", + "data-layout": "e-m:e-p:64:64-i64:64-n64-S128", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "arch": "riscv64", + "cpu": "generic-rv64", + "features": "", + "max-atomic-width": "32", + "linker": "riscv64-unknown-elf-ld", + "linker-flavor": "ld", + "pre-link-args": { + "ld": [ + "-Tboot/linker.ld", + "-melf64lriscv" + ] + }, + "executables": true, + "panic-strategy": "abort", + "relocation-model": "static", + "abi-blacklist": [ + "cdecl", + "stdcall", + "fastcall", + "vectorcall", + "thiscall", + "aapcs", + "win64", + "sysv64", + "ptx-kernel", + "msp430-interrupt", + "x86-interrupt" + ] +} diff --git a/kernel/src/arch/riscv64/atomic.patch b/kernel/src/arch/riscv64/atomic.patch new file mode 100644 index 0000000..ec7ca3a --- /dev/null +++ b/kernel/src/arch/riscv64/atomic.patch @@ -0,0 +1,57 @@ +--- atomic_backup.rs 2018-10-06 19:59:14.000000000 +0800 ++++ atomic.rs 2018-10-26 14:34:31.000000000 +0800 +@@ -125,6 +125,9 @@ + #[cfg(target_has_atomic = "8")] + #[stable(feature = "rust1", since = "1.0.0")] + pub struct AtomicBool { ++ #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] ++ v: UnsafeCell, ++ #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + v: UnsafeCell, + } + +@@ -265,6 +268,44 @@ + pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); + + #[cfg(target_has_atomic = "8")] ++#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] ++impl AtomicBool { ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub const fn new(v: bool) -> AtomicBool { ++ AtomicBool { v: UnsafeCell::new(v as u32) } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub fn load(&self, order: Ordering) -> bool { ++ unsafe { atomic_load(self.v.get(), order) != 0 } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ pub fn store(&self, val: bool, order: Ordering) { ++ unsafe { atomic_store(self.v.get(), val as u32, order); } ++ } ++ ++ /// ++ #[inline] ++ #[stable(feature = "rust1", since = "1.0.0")] ++ #[cfg(target_has_atomic = "cas")] ++ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { ++ loop { ++ if let Ok(val) = unsafe { atomic_compare_exchange(self.v.get(), current as u32, new as u32, order, order) } { ++ return val != 0; ++ } ++ } ++ } ++} ++ ++#[cfg(target_has_atomic = "8")] ++#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + impl AtomicBool { + /// Creates a new `AtomicBool`. + /// diff --git a/kernel/src/arch/riscv64/boot/boot.asm b/kernel/src/arch/riscv64/boot/boot.asm new file mode 100644 index 0000000..8af7045 --- /dev/null +++ b/kernel/src/arch/riscv64/boot/boot.asm @@ -0,0 +1,16 @@ + .section .text.boot +boot: + csrwi 0x304, 0 # mie + csrwi 0x344, 0 # mip + csrwi 0x340, 0 # mscratch + csrwi 0x180, 0 # satp + li t0, -1 + csrw 0x302, t0 # medeleg + csrw 0x303, t0 # mideleg + csrw 0x306, t0 # mcounteren + csrw 0x106, t0 # scounteren + li t0, 1 << 11 # MPP = S + csrw 0x300, t0 # mstatus + lui t0, 0x80020 + csrw 0x341, t0 # mepc + mret diff --git a/kernel/src/arch/riscv64/boot/entry.asm b/kernel/src/arch/riscv64/boot/entry.asm new file mode 100644 index 0000000..0485f0e --- /dev/null +++ b/kernel/src/arch/riscv64/boot/entry.asm @@ -0,0 +1,19 @@ + .section .text.entry + .globl _start +_start: + add t0, a0, 1 + slli t0, t0, 16 + + lui sp, %hi(bootstack) + addi sp, sp, %lo(bootstack) + add sp, sp, t0 + + call rust_main + + .section .bss + .align 12 #PGSHIFT + .global bootstack +bootstack: + .space 4096 * 16 * 8 + .global bootstacktop +bootstacktop: diff --git a/kernel/src/arch/riscv64/boot/linker.ld b/kernel/src/arch/riscv64/boot/linker.ld new file mode 100644 index 0000000..cd5de10 --- /dev/null +++ b/kernel/src/arch/riscv64/boot/linker.ld @@ -0,0 +1,57 @@ +/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ + +/* Simple linker script for the ucore kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0x80020000; + +SECTIONS +{ + . = 0x80000000; + .boot : { + KEEP(*(.text.boot)) + } + + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + *(.text .stub .text.* .gnu.linkonce.t.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.* .gnu.linkonce.r.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + . = ALIGN(4K); + edata = .; + } + + .bss : { + sbss = .; + *(.bss .bss.* .sbss*) + . = ALIGN(4K); + ebss = .; + } + + .got : { + *(.got .got.*) + . = ALIGN(4K); + } + + PROVIDE(end = .); +} diff --git a/kernel/src/arch/riscv64/boot/trap.asm b/kernel/src/arch/riscv64/boot/trap.asm new file mode 100644 index 0000000..0f3bc3d --- /dev/null +++ b/kernel/src/arch/riscv64/boot/trap.asm @@ -0,0 +1,127 @@ +# Constants / Macros defined in Rust code: +# xscratch +# xstatus +# xepc +# xcause +# xtval +# XRET + +.macro SAVE_ALL + # 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, (xscratch), sp + bnez sp, _save_context +_restore_kernel_sp: + csrr sp, (xscratch) + # sscratch = previous-sp, sp = kernel-sp +_save_context: + # provide room for trap frame + addi sp, sp, -36 * 4 + # save x registers except x2 (sp) + sw x1, 1*4(sp) + sw x3, 3*4(sp) + # tp(x4) = hartid. DON'T change. + # sw x4, 4*4(sp) + sw x5, 5*4(sp) + sw x6, 6*4(sp) + sw x7, 7*4(sp) + sw x8, 8*4(sp) + sw x9, 9*4(sp) + sw x10, 10*4(sp) + sw x11, 11*4(sp) + sw x12, 12*4(sp) + sw x13, 13*4(sp) + sw x14, 14*4(sp) + sw x15, 15*4(sp) + sw x16, 16*4(sp) + sw x17, 17*4(sp) + sw x18, 18*4(sp) + sw x19, 19*4(sp) + sw x20, 20*4(sp) + sw x21, 21*4(sp) + sw x22, 22*4(sp) + sw x23, 23*4(sp) + sw x24, 24*4(sp) + sw x25, 25*4(sp) + sw x26, 26*4(sp) + sw x27, 27*4(sp) + sw x28, 28*4(sp) + sw x29, 29*4(sp) + sw x30, 30*4(sp) + sw x31, 31*4(sp) + + # get sp, sstatus, sepc, stval, scause + # set sscratch = 0 + csrrw s0, (xscratch), x0 + csrr s1, (xstatus) + csrr s2, (xepc) + csrr s3, (xtval) + csrr s4, (xcause) + # store sp, sstatus, sepc, sbadvaddr, scause + sw s0, 2*4(sp) + sw s1, 32*4(sp) + sw s2, 33*4(sp) + sw s3, 34*4(sp) + sw s4, 35*4(sp) +.endm + +.macro RESTORE_ALL + lw s1, 32*4(sp) # s1 = sstatus + lw s2, 33*4(sp) # s2 = sepc + andi s0, s1, 1 << 8 + bnez s0, _restore_context # back to S-mode? (sstatus.SPP = 1) +_save_kernel_sp: + addi s0, sp, 36*4 + csrw (xscratch), s0 # sscratch = kernel-sp +_restore_context: + # restore sstatus, sepc + csrw (xstatus), s1 + csrw (xepc), s2 + + # restore x registers except x2 (sp) + lw x1, 1*4(sp) + lw x3, 3*4(sp) + # lw x4, 4*4(sp) + lw x5, 5*4(sp) + lw x6, 6*4(sp) + lw x7, 7*4(sp) + lw x8, 8*4(sp) + lw x9, 9*4(sp) + lw x10, 10*4(sp) + lw x11, 11*4(sp) + lw x12, 12*4(sp) + lw x13, 13*4(sp) + lw x14, 14*4(sp) + lw x15, 15*4(sp) + lw x16, 16*4(sp) + lw x17, 17*4(sp) + lw x18, 18*4(sp) + lw x19, 19*4(sp) + lw x20, 20*4(sp) + lw x21, 21*4(sp) + lw x22, 22*4(sp) + lw x23, 23*4(sp) + lw x24, 24*4(sp) + lw x25, 25*4(sp) + lw x26, 26*4(sp) + lw x27, 27*4(sp) + lw x28, 28*4(sp) + lw x29, 29*4(sp) + lw x30, 30*4(sp) + lw x31, 31*4(sp) + # restore sp last + lw x2, 2*4(sp) +.endm + + .section .text + .globl __alltraps +__alltraps: + SAVE_ALL + mv a0, sp + jal rust_trap + .globl __trapret +__trapret: + RESTORE_ALL + # return from supervisor call + XRET diff --git a/kernel/src/arch/riscv64/compiler_rt.c b/kernel/src/arch/riscv64/compiler_rt.c new file mode 100644 index 0000000..95c871f --- /dev/null +++ b/kernel/src/arch/riscv64/compiler_rt.c @@ -0,0 +1,38 @@ +// http://llvm.org/docs/Atomics.html#libcalls-atomic + +int __atomic_load_4(int *src) { + int res = 0; + __asm__ __volatile__("amoadd.w.rl %0, zero, (%1)" : "=r"(res) : "r"(src) : "memory"); + return res; +} + +int __atomic_store_4(int *dst, int val) { + __asm__ __volatile__("amoswap.w.aq zero, %0, (%1)" :: "r"(val), "r"(dst) : "memory"); +} + +char __atomic_compare_exchange_4(int* dst, int* expected, int desired) { + int val; + // val = *dst + __asm__ __volatile__("lr.w %0, (%1)" : "=r"(val) : "r"(dst) : "memory"); + if (val == *expected) { + int result; + // Try: *dst = desired. If success, result = 0, otherwise result != 0. + __asm__ __volatile__("sc.w %0, %1, (%2)" : "=r"(result) : "r"(desired), "r"(dst) : "memory"); + return result == 0; + } + // *expected should always equal to the previous value of *dst + *expected = val; + return 0; +} + +int __atomic_fetch_add_4(int* ptr, int val) { + int res; + __asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(val), "r"(ptr) : "memory"); + return res; +} + +int __atomic_fetch_sub_4(int* ptr, int val) { + int res; + __asm__ __volatile__("amoadd.w.rl %0, %1, (%2)" : "=r"(res) : "r"(-val), "r"(ptr) : "memory"); + return res; +} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/compiler_rt.rs b/kernel/src/arch/riscv64/compiler_rt.rs new file mode 100644 index 0000000..e8fff84 --- /dev/null +++ b/kernel/src/arch/riscv64/compiler_rt.rs @@ -0,0 +1,25 @@ +//! Workaround for missing compiler-builtin symbols +//! +//! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic) + +/// Copy from: +/// https://github.com/rust-lang-nursery/compiler-builtins/blob/master/src/riscv32.rs +#[no_mangle] +pub extern fn __mulsi3(mut a: u32, mut b: u32) -> u32 { + let mut r: u32 = 0; + + while a > 0 { + if a & 1 > 0 { + r += b; + } + a >>= 1; + b <<= 1; + } + + r +} + +#[no_mangle] +pub extern fn abort() { + loop {} +} diff --git a/kernel/src/arch/riscv64/consts.rs b/kernel/src/arch/riscv64/consts.rs new file mode 100644 index 0000000..40a8e6b --- /dev/null +++ b/kernel/src/arch/riscv64/consts.rs @@ -0,0 +1,14 @@ +// Physical address available on THINPAD: +// [0x80000000, 0x80800000] +const P2_SIZE: usize = 1 << 22; +const P2_MASK: usize = 0x3ff << 22; +pub const RECURSIVE_INDEX: usize = 0x3fe; +pub const KERNEL_OFFSET: usize = 0; +pub const KERNEL_P2_INDEX: usize = 0x8000_0000 >> 22; +pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000; +pub const MEMORY_OFFSET: usize = 0x8000_0000; +//pub const MEMORY_END: usize = 0x8080_0000; //for thinpad not enough now +pub const MEMORY_END: usize = 0x8100_0000; +pub const USER_STACK_OFFSET: usize = 0x70000000; +pub const USER_STACK_SIZE: usize = 0x10000; +pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET; \ No newline at end of file diff --git a/kernel/src/arch/riscv64/context.rs b/kernel/src/arch/riscv64/context.rs new file mode 100644 index 0000000..11c657b --- /dev/null +++ b/kernel/src/arch/riscv64/context.rs @@ -0,0 +1,277 @@ +#[cfg(feature = "m_mode")] +use riscv::register::{ + mstatus as xstatus, + mstatus::Mstatus as Xstatus, + mcause::Mcause, +}; +#[cfg(not(feature = "m_mode"))] +use riscv::register::{ + sstatus as xstatus, + sstatus::Sstatus as Xstatus, + mcause::Mcause, +}; + +#[derive(Clone)] +#[repr(C)] +pub struct TrapFrame { + pub x: [usize; 32], // general registers + pub sstatus: Xstatus, // Supervisor Status Register + pub sepc: usize, // Supervisor exception program counter, save the trap virtual address (here is used to save the process program entry addr?) + pub stval: usize, // Supervisor trap value + pub scause: Mcause, // scause register: record the cause of exception/interrupt/trap +} + +/// Generate the trapframe for building new thread in kernel +impl TrapFrame { + /* + * @param: + * entry: program entry for the thread + * arg: a0 + * sp: stack top + * @brief: + * generate a trapfram for building a new kernel thread + * @retval: + * the trapframe for new kernel thread + */ + fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.x[10] = arg; // a0 + tf.x[2] = sp; + tf.sepc = entry as usize; + tf.sstatus = xstatus::read(); + tf.sstatus.set_xpie(true); + tf.sstatus.set_xie(false); + #[cfg(feature = "m_mode")] + tf.sstatus.set_mpp(xstatus::MPP::Machine); + #[cfg(not(feature = "m_mode"))] + tf.sstatus.set_spp(xstatus::SPP::Supervisor); + tf + } + + /* + * @param: + * entry_addr: program entry for the thread + * sp: stack top + * @brief: + * generate a trapfram for building a new user thread + * @retval: + * the trapframe for new user thread + */ + fn new_user_thread(entry_addr: usize, sp: usize) -> Self { + use core::mem::zeroed; + let mut tf: Self = unsafe { zeroed() }; + tf.x[2] = sp; + tf.sepc = entry_addr; + tf.sstatus = xstatus::read(); + tf.sstatus.set_xpie(true); + tf.sstatus.set_xie(false); + #[cfg(feature = "m_mode")] + tf.sstatus.set_mpp(xstatus::MPP::User); + #[cfg(not(feature = "m_mode"))] + tf.sstatus.set_spp(xstatus::SPP::User); + tf + } +} + +use core::fmt::{Debug, Formatter, Error}; +impl Debug for TrapFrame { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + struct Regs<'a>(&'a [usize; 32]); + impl<'a> Debug for Regs<'a> { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + const REG_NAME: [&str; 32] = [ + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "t3", "t4", "t5", "t6"]; + f.debug_map().entries(REG_NAME.iter().zip(self.0)).finish() + } + } + f.debug_struct("TrapFrame") + .field("regs", &Regs(&self.x)) + .field("sstatus", &self.sstatus) + .field("sepc", &self.sepc) + .field("stval", &self.stval) + .field("scause", &self.scause) + .finish() + } +} + +/// kernel stack contents for a new thread +#[derive(Debug)] +#[repr(C)] +pub struct InitStack { + context: ContextData, + tf: TrapFrame, +} + +impl InitStack { + /* + * @param: + * stack_top: the pointer to kernel stack stop + * @brief: + * save the InitStack on the kernel stack stop + * @retval: + * a Context with ptr in it + */ + unsafe fn push_at(self, stack_top: usize) -> Context { + let ptr = (stack_top as *mut Self).offset(-1); //real kernel stack top + *ptr = self; + Context(ptr as usize) + } +} + +extern { + fn __trapret(); +} + +#[derive(Debug, Default)] +#[repr(C)] +struct ContextData { + ra: usize, + satp: usize, + s: [usize; 12], +} + +impl ContextData { + fn new(satp: usize) -> Self { + // satp(asid) just like cr3, save the physical address for Page directory? + ContextData { ra: __trapret as usize, satp, ..ContextData::default() } + } +} + +/// A struct only contain one usize element +#[derive(Debug)] +pub struct Context(usize); + +impl Context { + /// Switch to another kernel thread. + /// + /// Defined in `trap.asm`. + /// + /// Push all callee-saved registers at the current kernel stack. + /// Store current sp, switch to target. + /// Pop all callee-saved registers, then return to the target. + #[naked] + #[inline(never)] + pub unsafe extern fn switch(&mut self, target: &mut Self) { + asm!( + " + // save from's registers + addi sp, sp, -4*14 + sw sp, 0(a0) + sw ra, 0*4(sp) + sw s0, 2*4(sp) + sw s1, 3*4(sp) + sw s2, 4*4(sp) + sw s3, 5*4(sp) + sw s4, 6*4(sp) + sw s5, 7*4(sp) + sw s6, 8*4(sp) + sw s7, 9*4(sp) + sw s8, 10*4(sp) + sw s9, 11*4(sp) + sw s10, 12*4(sp) + sw s11, 13*4(sp) + csrrs s11, 0x180, x0 // satp + sw s11, 1*4(sp) + + // restore to's registers + lw sp, 0(a1) + lw s11, 1*4(sp) + csrrw x0, 0x180, s11 // satp + lw ra, 0*4(sp) + lw s0, 2*4(sp) + lw s1, 3*4(sp) + lw s2, 4*4(sp) + lw s3, 5*4(sp) + lw s4, 6*4(sp) + lw s5, 7*4(sp) + lw s6, 8*4(sp) + lw s7, 9*4(sp) + lw s8, 10*4(sp) + lw s9, 11*4(sp) + lw s10, 12*4(sp) + lw s11, 13*4(sp) + addi sp, sp, 4*14 + + sw zero, 0(a1) + ret" + : : : : "volatile" ) + } + + /* + * @brief: + * generate a null Context + * @retval: + * a null Context + */ + pub unsafe fn null() -> Self { + Context(0) + } + + /* + * @param: + * entry: program entry for the thread + * arg: a0 + * kstack_top: kernel stack top + * cr3: cr3 register, save the physical address of Page directory + * @brief: + * generate the content of kernel stack for the new kernel thread and save it's address at kernel stack top - 1 + * @retval: + * a Context struct with the pointer to the kernel stack top - 1 as its only element + */ + pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, cr3: usize) -> Self { + InitStack { + context: ContextData::new(cr3), + tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top), + }.push_at(kstack_top) + } + + /* + * @param: + * entry_addr: program entry for the thread + * ustack_top: user stack top + * kstack_top: kernel stack top + * is32: whether the cpu is 32 bit or not + * cr3: cr3 register, save the physical address of Page directory + * @brief: + * generate the content of kernel stack for the new user thread and save it's address at kernel stack top - 1 + * @retval: + * a Context struct with the pointer to the kernel stack top - 1 as its only element + */ + pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, cr3: usize) -> Self { + InitStack { + context: ContextData::new(cr3), + tf: TrapFrame::new_user_thread(entry_addr, ustack_top), + }.push_at(kstack_top) + } + + /* + * @param: + * TrapFrame: the trapframe of the forked process(thread) + * kstack_top: kernel stack top + * cr3: cr3 register, save the physical address of Page directory + * @brief: + * fork and generate a new process(thread) Context according to the TrapFrame and save it's address at kernel stack top - 1 + * @retval: + * a Context struct with the pointer to the kernel stack top - 1 as its only element + */ + pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, cr3: usize) -> Self { + InitStack { + context: ContextData::new(cr3), + tf: { + let mut tf = tf.clone(); + // fork function's ret value, the new process is 0 + tf.x[10] = 0; // a0 + tf + }, + }.push_at(kstack_top) + } + /// Called at a new user context + /// To get the init TrapFrame in sys_exec + pub unsafe fn get_init_tf(&self) -> TrapFrame { + (*(self.0 as *const InitStack)).tf.clone() + } +} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/cpu.rs b/kernel/src/arch/riscv64/cpu.rs new file mode 100644 index 0000000..0f21646 --- /dev/null +++ b/kernel/src/arch/riscv64/cpu.rs @@ -0,0 +1,36 @@ +use crate::consts::MAX_CPU_NUM; +use core::ptr::{read_volatile, write_volatile}; +use crate::memory::*; + +static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; + +pub unsafe fn set_cpu_id(cpu_id: usize) { + asm!("mv tp, $0" : : "r"(cpu_id)); +} + +pub fn id() -> usize { + let cpu_id; + unsafe { asm!("mv $0, tp" : "=r"(cpu_id)); } + cpu_id +} + +pub fn send_ipi(cpu_id: usize) { + bbl::sbi::send_ipi(1 << cpu_id); +} + +pub unsafe fn has_started(cpu_id: usize) -> bool { + read_volatile(&STARTED[cpu_id]) +} + +pub unsafe fn start_others(hart_mask: usize) { + for cpu_id in 0..MAX_CPU_NUM { + if (hart_mask >> cpu_id) & 1 != 0 { + write_volatile(&mut STARTED[cpu_id], true); + } + } +} + +pub fn halt() { + use riscv::asm::wfi; + unsafe { wfi() } +} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/interrupt.rs b/kernel/src/arch/riscv64/interrupt.rs new file mode 100644 index 0000000..22a3674 --- /dev/null +++ b/kernel/src/arch/riscv64/interrupt.rs @@ -0,0 +1,171 @@ +#[cfg(feature = "m_mode")] +use riscv::register::{ + mstatus as xstatus, + mscratch as xscratch, + mtvec as xtvec, +}; +#[cfg(not(feature = "m_mode"))] +use riscv::register::{ + sstatus as xstatus, + sscratch as xscratch, + stvec as xtvec, +}; +use riscv::register::{mcause, mepc, sie}; +pub use self::context::*; +use crate::memory::{MemorySet, InactivePageTable0}; +use log::*; + +#[path = "context.rs"] +mod context; + +/* +* @brief: +* initialize the interrupt status +*/ +pub fn init() { + extern { + fn __alltraps(); + } + unsafe { + // Set sscratch register to 0, indicating to exception vector that we are + // presently executing in the kernel + xscratch::write(0); + // Set the exception vector address + xtvec::write(__alltraps as usize, xtvec::TrapMode::Direct); + // Enable IPI + sie::set_ssoft(); + // Enable serial interrupt + sie::set_sext(); + // NOTE: In M-mode: mie.MSIE is set by BBL. + // mie.MEIE can not be set in QEMU v3.0 + // (seems like a bug) + } + info!("interrupt: init end"); +} + +/* +* @brief: +* enable interrupt +*/ +#[inline(always)] +pub unsafe fn enable() { + xstatus::set_xie(); +} + +/* +* @brief: +* store and disable interrupt +* @retbal: +* a usize value store the origin sie +*/ +#[inline(always)] +pub unsafe fn disable_and_store() -> usize { + let e = xstatus::read().xie() as usize; + xstatus::clear_xie(); + e +} + +/* +* @param: +* flags: input flag +* @brief: +* enable interrupt if flags != 0 +*/ +#[inline(always)] +pub unsafe fn restore(flags: usize) { + if flags != 0 { + xstatus::set_xie(); + } +} + +/* +* @param: +* TrapFrame: the trapFrame of the Interrupt/Exception/Trap to be processed +* @brief: +* process the Interrupt/Exception/Trap +*/ +#[no_mangle] +pub extern fn rust_trap(tf: &mut TrapFrame) { + use self::mcause::{Trap, Interrupt as I, Exception as E}; + trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause()); + match tf.scause.cause() { + // M-mode only + Trap::Interrupt(I::MachineExternal) => serial(), + Trap::Interrupt(I::MachineSoft) => ipi(), + Trap::Interrupt(I::MachineTimer) => timer(), + Trap::Exception(E::MachineEnvCall) => sbi(tf), + + Trap::Interrupt(I::SupervisorExternal) => serial(), + Trap::Interrupt(I::SupervisorSoft) => ipi(), + Trap::Interrupt(I::SupervisorTimer) => timer(), + Trap::Exception(E::IllegalInstruction) => illegal_inst(tf), + Trap::Exception(E::UserEnvCall) => syscall(tf), + Trap::Exception(E::LoadPageFault) => page_fault(tf), + Trap::Exception(E::StorePageFault) => page_fault(tf), + Trap::Exception(E::InstructionPageFault) => page_fault(tf), + _ => crate::trap::error(tf), + } + trace!("Interrupt end"); +} + +/// Call BBL SBI functions for M-mode kernel +fn sbi(tf: &mut TrapFrame) { + (super::BBL.mcall_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc); + tf.sepc += 4; +} + +fn serial() { + crate::trap::serial(super::io::getchar()); +} + +fn ipi() { + debug!("IPI"); + bbl::sbi::clear_ipi(); +} + +/* +* @brief: +* process timer interrupt +*/ +fn timer() { + super::timer::set_next(); + crate::trap::timer(); +} + +/* +* @param: +* TrapFrame: the Trapframe for the syscall +* @brief: +* process syscall +*/ +fn syscall(tf: &mut TrapFrame) { + tf.sepc += 4; // Must before syscall, because of fork. + let ret = crate::syscall::syscall(tf.x[10], [tf.x[11], tf.x[12], tf.x[13], tf.x[14], tf.x[15], tf.x[16]], tf); + tf.x[10] = ret as usize; +} + +/* +* @param: +* TrapFrame: the Trapframe for the illegal inst exception +* @brief: +* process IllegalInstruction exception +*/ +fn illegal_inst(tf: &mut TrapFrame) { + (super::BBL.illegal_insn_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc); + tf.sepc = mepc::read(); +} + +/* +* @param: +* TrapFrame: the Trapframe for the page fault exception +* @brief: +* process page fault exception +*/ +fn page_fault(tf: &mut TrapFrame) { + let addr = tf.stval; + trace!("\nEXCEPTION: Page Fault @ {:#x}", addr); + + if !crate::memory::page_fault_handler(addr) { + crate::trap::error(tf); + } +} diff --git a/kernel/src/arch/riscv64/io.rs b/kernel/src/arch/riscv64/io.rs new file mode 100644 index 0000000..b2c49d2 --- /dev/null +++ b/kernel/src/arch/riscv64/io.rs @@ -0,0 +1,60 @@ +use core::fmt::{Write, Result, Arguments}; +use core::ptr::{read_volatile, write_volatile}; +use bbl::sbi; + +struct SerialPort; + +impl Write for SerialPort { + fn write_str(&mut self, s: &str) -> Result { + for c in s.bytes() { + if c == 127 { + putchar(8); + putchar(b' '); + putchar(8); + } else { + putchar(c); + } + } + Ok(()) + } +} + +fn putchar(c: u8) { + if cfg!(feature = "no_bbl") { + unsafe { + while read_volatile(STATUS) & CAN_WRITE == 0 {} + write_volatile(DATA, c as u8); + } + } else if cfg!(feature = "m_mode") { + (super::BBL.mcall_console_putchar)(c); + } else { + sbi::console_putchar(c as usize); + } +} + +pub fn getchar() -> char { + let c = if cfg!(feature = "no_bbl") { + unsafe { + // while read_volatile(STATUS) & CAN_READ == 0 {} + read_volatile(DATA) + } + } else if cfg!(feature = "m_mode") { + (super::BBL.mcall_console_getchar)() as u8 + } else { + sbi::console_getchar() as u8 + }; + + match c { + 255 => '\0', // null + c => c as char, + } +} + +pub fn putfmt(fmt: Arguments) { + SerialPort.write_fmt(fmt).unwrap(); +} + +const DATA: *mut u8 = 0x10000000 as *mut u8; +const STATUS: *const u8 = 0x10000005 as *const u8; +const CAN_READ: u8 = 1 << 0; +const CAN_WRITE: u8 = 1 << 5; diff --git a/kernel/src/arch/riscv64/memory.rs b/kernel/src/arch/riscv64/memory.rs new file mode 100644 index 0000000..7ba0b9f --- /dev/null +++ b/kernel/src/arch/riscv64/memory.rs @@ -0,0 +1,110 @@ +use core::{slice, mem}; +use riscv::{addr::*, register::sstatus}; +use ucore_memory::PAGE_SIZE; +use log::*; +use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, MEMORY_ALLOCATOR}; +use crate::consts::{MEMORY_OFFSET, MEMORY_END}; + +#[cfg(feature = "no_mmu")] +pub fn init() { + init_heap(); + + let heap_bottom = end as usize; + let heap_size = MEMORY_END - heap_bottom; + unsafe { MEMORY_ALLOCATOR.lock().init(heap_bottom, heap_size); } + info!("available memory: [{:#x}, {:#x})", heap_bottom, MEMORY_END); +} + +/* +* @brief: +* Init the mermory management module, allow memory access and set up page table and init heap and frame allocator +*/ +#[cfg(not(feature = "no_mmu"))] +pub fn init() { + #[repr(align(4096))] // align the PageData struct to 4096 bytes + struct PageData([u8; PAGE_SIZE]); + static PAGE_TABLE_ROOT: PageData = PageData([0; PAGE_SIZE]); + + unsafe { sstatus::set_sum(); } // Allow user memory access + let frame = Frame::of_addr(PhysAddr::new(&PAGE_TABLE_ROOT as *const _ as u32)); + super::paging::setup_page_table(frame); // set up page table + // initialize heap and Frame allocator + init_frame_allocator(); + init_heap(); + // remap the kernel use 4K page + remap_the_kernel(); +} + +pub fn init_other() { + unsafe { + sstatus::set_sum(); // Allow user memory access + asm!("csrw 0x180, $0; sfence.vma" :: "r"(SATP) :: "volatile"); + } +} + +/* +* @brief: +* Init frame allocator, here use a BitAlloc implemented by segment tree. +*/ +fn init_frame_allocator() { + use bit_allocator::BitAlloc; + use core::ops::Range; + + let mut ba = FRAME_ALLOCATOR.lock(); + ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END)); + info!("FrameAllocator init end"); + + /* + * @param: + * start: start address + * end: end address + * @brief: + * transform the memory address to the page number + * @retval: + * the page number range from start address to end address + */ + fn to_range(start: usize, end: usize) -> Range { + let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE; + let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1; + page_start..page_end + } +} + +/* +* @brief: +* remmap the kernel memory address with 4K page recorded in p1 page table +*/ +#[cfg(not(feature = "no_mmu"))] +fn remap_the_kernel() { + let mut ms = MemorySet::new_bare(); + #[cfg(feature = "no_bbl")] + ms.push(MemoryArea::new_identity(0x10000000, 0x10000008, MemoryAttr::default(), "serial")); + ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text")); + ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data")); + ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata")); + ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss")); + unsafe { ms.activate(); } + unsafe { SATP = ms.token(); } + mem::forget(ms); + info!("kernel remap end"); +} + +// First core stores its SATP here. +// Other cores load it later. +static mut SATP: usize = 0; + +// Symbols provided by linker script +extern { + fn stext(); + fn etext(); + fn sdata(); + fn edata(); + fn srodata(); + fn erodata(); + fn sbss(); + fn ebss(); + fn start(); + fn end(); + fn bootstack(); + fn bootstacktop(); +} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs new file mode 100644 index 0000000..eb2a17a --- /dev/null +++ b/kernel/src/arch/riscv64/mod.rs @@ -0,0 +1,81 @@ +pub mod io; +pub mod interrupt; +pub mod timer; +pub mod paging; +pub mod memory; +pub mod compiler_rt; +pub mod consts; +pub mod cpu; + +#[no_mangle] +pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize, functions: usize) -> ! { + unsafe { cpu::set_cpu_id(hartid); } + unsafe { BBL_FUNCTIONS_PTR = functions as *const _; } + println!("Hello RISCV! in hart {}, dtb @ {:#x}, functions @ {:#x}", hartid, dtb, functions); + + if hartid != 0 { + while unsafe { !cpu::has_started(hartid) } { } + others_main(); + unreachable!(); + } + + crate::logging::init(); + interrupt::init(); + memory::init(); + timer::init(); + crate::process::init(); + + unsafe { cpu::start_others(hart_mask); } + crate::kmain(); +} + +fn others_main() -> ! { + interrupt::init(); + memory::init_other(); + timer::init(); + crate::kmain(); +} + + +/// Constant & Macro for `trap.asm` +#[cfg(feature = "m_mode")] +global_asm!(" + .equ xstatus, 0x300 + .equ xscratch, 0x340 + .equ xepc, 0x341 + .equ xcause, 0x342 + .equ xtval, 0x343 + .macro XRET\n mret\n .endm +"); +#[cfg(not(feature = "m_mode"))] +global_asm!(" + .equ xstatus, 0x100 + .equ xscratch, 0x140 + .equ xepc, 0x141 + .equ xcause, 0x142 + .equ xtval, 0x143 + .macro XRET\n sret\n .endm +"); + +#[cfg(feature = "no_bbl")] +global_asm!(include_str!("boot/boot.asm")); +global_asm!(include_str!("boot/entry.asm")); +global_asm!(include_str!("boot/trap.asm")); + + +/// Some symbols passed from BBL. +/// Used in M-mode kernel. +#[repr(C)] +struct BBLFunctions { + mcall_trap: BBLTrapHandler, + illegal_insn_trap: BBLTrapHandler, + mcall_console_putchar: extern fn(u8), + mcall_console_getchar: extern fn() -> usize, +} + +type BBLTrapHandler = extern fn(regs: *const usize, mcause: usize, mepc: usize); +static mut BBL_FUNCTIONS_PTR: *const BBLFunctions = ::core::ptr::null(); +use lazy_static::lazy_static; +lazy_static! { + static ref BBL: BBLFunctions = unsafe { BBL_FUNCTIONS_PTR.read() }; +} \ No newline at end of file diff --git a/kernel/src/arch/riscv64/paging.rs b/kernel/src/arch/riscv64/paging.rs new file mode 100644 index 0000000..6cce3f3 --- /dev/null +++ b/kernel/src/arch/riscv64/paging.rs @@ -0,0 +1,371 @@ +use crate::consts::{KERNEL_P2_INDEX, RECURSIVE_INDEX}; +// Depends on kernel +use crate::memory::{active_table, alloc_frame, dealloc_frame}; +use riscv::addr::*; +use riscv::asm::{sfence_vma, sfence_vma_all}; +use riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable}; +use riscv::paging::{FrameAllocator, FrameDeallocator}; +use riscv::register::satp; +use ucore_memory::memory_set::*; +use ucore_memory::PAGE_SIZE; +use ucore_memory::paging::*; +use log::*; + +/* +* @param: +* Frame: page table root frame +* @brief: +* setup page table in the frame +*/ +// need 1 page +pub fn setup_page_table(frame: Frame) { + let p2 = unsafe { &mut *(frame.start_address().as_u32() as *mut RvPageTable) }; + p2.zero(); + p2.set_recursive(RECURSIVE_INDEX, frame.clone()); + + // Set kernel identity map + // 0x10000000 ~ 1K area + p2.map_identity(0x40, EF::VALID | EF::READABLE | EF::WRITABLE); + // 0x80000000 ~ 12M area + p2.map_identity(KERNEL_P2_INDEX, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); + p2.map_identity(KERNEL_P2_INDEX + 1, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); + p2.map_identity(KERNEL_P2_INDEX + 2, EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE); + + use riscv::register::satp; + unsafe { satp::set(satp::Mode::Sv32, 0, frame); } + sfence_vma_all(); + info!("setup init page table end"); +} + +pub struct ActivePageTable(RecursivePageTable<'static>); + +pub struct PageEntry(PageTableEntry); + +impl PageTable for ActivePageTable { + type Entry = PageEntry; + + /* + * @param: + * addr: the virtual addr to be matched + * target: the physical addr to be matched with addr + * @brief: + * map the virtual address 'addr' to the physical address 'target' in pagetable. + * @retval: + * the matched PageEntry + */ + fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry { + // the flag for the new page entry + let flags = EF::VALID | EF::READABLE | EF::WRITABLE; + // here page is for the virtual address while frame is for the physical, both of them is 4096 bytes align + let page = Page::of_addr(VirtAddr::new(addr)); + let frame = Frame::of_addr(PhysAddr::new(target as u32)); + // map the page to the frame using FrameAllocatorForRiscv + // we may need frame allocator to alloc frame for new page table(first/second) + self.0.map_to(page, frame, flags, &mut FrameAllocatorForRiscv) + .unwrap().flush(); + self.get_entry(addr).expect("fail to get entry") + } + + /* + * @param: + * addr: virtual address of which the mapped physical frame should be unmapped + * @bridf: + ^ unmap the virtual addresses' mapped physical frame + */ + fn unmap(&mut self, addr: usize) { + let page = Page::of_addr(VirtAddr::new(addr)); + let (frame, flush) = self.0.unmap(page).unwrap(); + flush.flush(); + } + + /* + * @param: + * addr:input virtual address + * @brief: + * get the pageEntry of 'addr' + * @retval: + * a mutable PageEntry reference of 'addr' + */ + fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> { + if unsafe { !(*ROOT_PAGE_TABLE)[addr >> 22].flags().contains(EF::VALID) } { + return None; + } + let page = Page::of_addr(VirtAddr::new(addr)); + // ??? + let _ = self.0.translate_page(page); + let entry_addr = ((addr >> 10) & ((1 << 22) - 4)) | (RECURSIVE_INDEX << 22); + unsafe { Some(&mut *(entry_addr as *mut PageEntry)) } + } + + /* + * @param: + * addr:the input (virutal) address + * @brief: + * get the addr's memory page slice + * @retval: + * a mutable reference slice of 'addr' 's page + */ + fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] { + use core::slice; + unsafe { slice::from_raw_parts_mut((addr & !(PAGE_SIZE - 1)) as *mut u8, PAGE_SIZE) } + } + + /* + * @param: + * addr: virtual address + * @brief: + * get the address's content + * @retval: + * the content(u8) of 'addr' + */ + fn read(&mut self, addr: usize) -> u8 { + unsafe { *(addr as *const u8) } + } + + /* + * @param: + * addr: virtual address + * @brief: + * write the address's content + */ + fn write(&mut self, addr: usize, data: u8) { + unsafe { *(addr as *mut u8) = data; } + } +} + +// define the ROOT_PAGE_TABLE, and the virtual address of it? +const ROOT_PAGE_TABLE: *mut RvPageTable = + (((RECURSIVE_INDEX << 10) | (RECURSIVE_INDEX + 1)) << 12) as *mut RvPageTable; + +impl ActivePageTable { + pub unsafe fn new() -> Self { + ActivePageTable(RecursivePageTable::new(&mut *ROOT_PAGE_TABLE).unwrap()) + } + + /* + * @param: + * frame: the target physical frame which will be temporarily mapped + * f: the function you would like to apply for once + * @brief: + * do something on the target physical frame? + */ + fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut RvPageTable)) { + // Create a temporary page + let page = Page::of_addr(VirtAddr::new(0xcafebabe)); + assert!(self.0.translate_page(page).is_none(), "temporary page is already mapped"); + // Map it to table + self.map(page.start_address().as_usize(), frame.start_address().as_u32() as usize); + // Call f + let table = unsafe { &mut *(page.start_address().as_usize() as *mut _) }; + f(self, table); + // Unmap the page + self.unmap(0xcafebabe); + } +} +/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs +impl Entry for PageEntry { + fn update(&mut self) { + let addr = VirtAddr::new((self as *const _ as usize) << 10); + sfence_vma(0, addr); + } + fn accessed(&self) -> bool { self.0.flags().contains(EF::ACCESSED) } + fn dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) } + fn writable(&self) -> bool { self.0.flags().contains(EF::WRITABLE) } + fn present(&self) -> bool { self.0.flags().contains(EF::VALID | EF::READABLE) } + fn clear_accessed(&mut self) { self.as_flags().remove(EF::ACCESSED); } + fn clear_dirty(&mut self) { self.as_flags().remove(EF::DIRTY); } + fn set_writable(&mut self, value: bool) { self.as_flags().set(EF::WRITABLE, value); } + fn set_present(&mut self, value: bool) { self.as_flags().set(EF::VALID | EF::READABLE, value); } + fn target(&self) -> usize { self.0.addr().as_u32() as usize } + fn set_target(&mut self, target: usize) { + let flags = self.0.flags(); + let frame = Frame::of_addr(PhysAddr::new(target as u32)); + self.0.set(frame, flags); + } + fn writable_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED1) } + fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::RESERVED2) } + fn set_shared(&mut self, writable: bool) { + let flags = self.as_flags(); + flags.set(EF::RESERVED1, writable); + flags.set(EF::RESERVED2, !writable); + } + fn clear_shared(&mut self) { self.as_flags().remove(EF::RESERVED1 | EF::RESERVED2); } + fn swapped(&self) -> bool { self.0.flags().contains(EF::RESERVED1) } + fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::RESERVED1, value); } + fn user(&self) -> bool { self.0.flags().contains(EF::USER) } + fn set_user(&mut self, value: bool) { self.as_flags().set(EF::USER, value); } + fn execute(&self) -> bool { self.0.flags().contains(EF::EXECUTABLE) } + fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::EXECUTABLE, value); } + fn mmio(&self) -> bool { unimplemented!() } + fn set_mmio(&mut self, value: bool) { unimplemented!() } +} + +impl PageEntry { + fn as_flags(&mut self) -> &mut EF { + unsafe { &mut *(self as *mut _ as *mut EF) } + } +} + +#[derive(Debug)] +pub struct InactivePageTable0 { + p2_frame: Frame, +} + +impl InactivePageTable for InactivePageTable0 { + type Active = ActivePageTable; + + /* + * @brief: + * get a new pagetable (for a new process or thread) + * @retbal: + * the new pagetable + */ + fn new() -> Self { + let mut pt = Self::new_bare(); + pt.map_kernel(); + pt + } + + /* + * @brief: + * allocate a new frame and then self-mapping it and regard it as the inactivepagetale + * retval: + * the inactive page table + */ + fn new_bare() -> Self { + let frame = Self::alloc_frame().map(|target| Frame::of_addr(PhysAddr::new(target as u32))) + .expect("failed to allocate frame"); + active_table().with_temporary_map(&frame, |_, table: &mut RvPageTable| { + table.zero(); + table.set_recursive(RECURSIVE_INDEX, frame.clone()); + }); + InactivePageTable0 { p2_frame: frame } + } + + /* + * @param: + * f: a function to do something with the temporary modified activate page table + * @brief: + * temporarily map the inactive pagetable as an active p2page and apply f on the temporary modified active page table + */ + fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) { + active_table().with_temporary_map(&satp::read().frame(), |active_table, p2_table: &mut RvPageTable| { + let backup = p2_table[RECURSIVE_INDEX].clone(); + + // overwrite recursive mapping + p2_table[RECURSIVE_INDEX].set(self.p2_frame.clone(), EF::VALID); + sfence_vma_all(); + + // execute f in the new context + f(active_table); + + // restore recursive mapping to original p2 table + p2_table[RECURSIVE_INDEX] = backup; + sfence_vma_all(); + }); + } + + /* + * @brief: + * active self as the current active page table + */ + unsafe fn activate(&self) { + let old_frame = satp::read().frame(); + let new_frame = self.p2_frame.clone(); + debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); + if old_frame != new_frame { + satp::set(satp::Mode::Sv32, 0, new_frame); + sfence_vma_all(); + } + } + + /* + * @param: + * f: the function to run when temporarily activate self as current page table + * @brief: + * Temporarily activate self and run the process, and return the return value of f + * @retval: + * the return value of f + */ + unsafe fn with(&self, f: impl FnOnce() -> T) -> T { + let old_frame = satp::read().frame(); + let new_frame = self.p2_frame.clone(); + debug!("switch table {:x?} -> {:x?}", old_frame, new_frame); + if old_frame != new_frame { + satp::set(satp::Mode::Sv32, 0, new_frame); + sfence_vma_all(); + } + let target = f(); + debug!("switch table {:x?} -> {:x?}", new_frame, old_frame); + if old_frame != new_frame { + satp::set(satp::Mode::Sv32, 0, old_frame); + sfence_vma_all(); + } + target + } + + /* + * @brief: + * get the token of self, the token is self's pagetable frame's starting physical address + * @retval: + * self token + */ + fn token(&self) -> usize { + self.p2_frame.number() | (1 << 31) // as satp + } + + fn alloc_frame() -> Option { + alloc_frame() + } + + fn dealloc_frame(target: usize) { + dealloc_frame(target) + } +} + +impl InactivePageTable0 { + /* + * @brief: + * map the kernel code memory address (p2 page table) in the new inactive page table according the current active page table + */ + fn map_kernel(&mut self) { + let table = unsafe { &mut *ROOT_PAGE_TABLE }; + let e0 = table[0x40]; + let e1 = table[KERNEL_P2_INDEX]; + assert!(!e1.is_unused()); + // for larger heap memroy + let e2 = table[KERNEL_P2_INDEX + 1]; + assert!(!e2.is_unused()); + let e3 = table[KERNEL_P2_INDEX + 2]; + assert!(!e2.is_unused()); + + self.edit(|_| { + table[0x40] = e0; + table[KERNEL_P2_INDEX].set(e1.frame(), EF::VALID | EF::GLOBAL); + // for larger heap memroy + table[KERNEL_P2_INDEX + 1].set(e2.frame(), EF::VALID | EF::GLOBAL); + table[KERNEL_P2_INDEX + 2].set(e3.frame(), EF::VALID | EF::GLOBAL); + }); + } +} + +impl Drop for InactivePageTable0 { + fn drop(&mut self) { + info!("PageTable dropping: {:?}", self); + Self::dealloc_frame(self.p2_frame.start_address().as_u32() as usize); + } +} + +struct FrameAllocatorForRiscv; + +impl FrameAllocator for FrameAllocatorForRiscv { + fn alloc(&mut self) -> Option { + alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr as u32))) + } +} + +impl FrameDeallocator for FrameAllocatorForRiscv { + fn dealloc(&mut self, frame: Frame) { + dealloc_frame(frame.start_address().as_u32() as usize); + } +} diff --git a/kernel/src/arch/riscv64/timer.rs b/kernel/src/arch/riscv64/timer.rs new file mode 100644 index 0000000..7588deb --- /dev/null +++ b/kernel/src/arch/riscv64/timer.rs @@ -0,0 +1,67 @@ +use riscv::register::*; +use bbl::sbi; +use log::*; + +/* +* @brief: +* get timer cycle for 64 bit cpu +*/ +#[cfg(target_pointer_width = "64")] +pub fn get_cycle() -> u64 { + time::read() as u64 +} + +/* +* @brief: +* get timer cycle for 32 bit cpu +*/ +#[cfg(target_pointer_width = "32")] +pub fn get_cycle() -> u64 { + loop { + let hi = timeh::read(); + let lo = time::read(); + let tmp = timeh::read(); + if hi == tmp { + return ((hi as u64) << 32) | (lo as u64); + } + } +} + +/* +* @brief: +* enable supervisor timer interrupt and set next timer interrupt +*/ +pub fn init() { + // Enable supervisor timer interrupt + #[cfg(feature = "m_mode")] + unsafe { mie::set_mtimer(); } + #[cfg(not(feature = "m_mode"))] + unsafe { sie::set_stimer(); } + + set_next(); + info!("timer: init end"); +} + +/* +* @brief: +* set the next timer interrupt +*/ +pub fn set_next() { + // 100Hz @ QEMU + let timebase = 250000; + set_timer(get_cycle() + timebase); +} + +/* +* @brief: +* set time for timer interrupt +*/ +fn set_timer(t: u64) { + #[cfg(feature = "no_bbl")] + unsafe { + asm!("csrw 0x321, $0; csrw 0x322, $1" + : : "r"(t as u32), "r"((t >> 32) as u32) : : "volatile"); + } + #[cfg(not(feature = "no_bbl"))] + sbi::set_timer(t); +} \ No newline at end of file