diff --git a/.cargo/config.toml b/.cargo/config.toml index 867d1a6b..ab9edbbb 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,6 +2,13 @@ # 使用系统 git 拉取依赖,可利用已配置的 git 凭证(如 gh auth、credential helper) git-fetch-with-cli = true +[target.x86_64-unknown-none] +rustflags = [ + "-Clink-args=-no-pie", + "-Clink-args=-znostart-stop-gc", + "-Clink-args=-Tlink.x", +] + [target.aarch64-unknown-none-softfloat] rustflags = [ "-Crelocation-model=pic", @@ -10,15 +17,15 @@ rustflags = [ "-Clink-args=-Taxplat.x", ] -[target.'cfg(target_os = "none")'] -runner = "cargo osrun" - -[target.x86_64-unknown-none] +[target.riscv64gc-unknown-none-elf] rustflags = [ "-Clink-args=-no-pie", "-Clink-args=-znostart-stop-gc", "-Clink-args=-Tlink.x", ] +[target.'cfg(target_os = "none")'] +runner = "cargo osrun" + [alias] -xtask = "run --bin xtask --no-default-features --features xtask --" +xtask = "run --bin xtask --" diff --git a/.github/workflows/qemu-riscv64.toml b/.github/workflows/qemu-riscv64.toml new file mode 100644 index 00000000..b228b6f1 --- /dev/null +++ b/.github/workflows/qemu-riscv64.toml @@ -0,0 +1,24 @@ +args = [ + "-nographic", + "-cpu", + "rv64", + "-machine", + "virt", + "-bios", + "default", + "-smp", + "4", + "-device", + "virtio-blk-device,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspaceFolder}/tmp/rootfs.img", + "-m", + "8g", +] +fail_regex = [] +success_regex = [ + "Hello, world!", + "test pass!", +] +to_bin = true +uefi = false \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 6d5015bc..4c69006f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,7 +193,7 @@ dependencies = [ "axdriver", "axerrno 0.2.2", "axfeat", - "axfs", + "axfs 0.2.0", "axhal", "axio", "axlog", @@ -208,6 +208,8 @@ version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e30c6a0ffd23095c69f48afd996eb51156b2511b52a01bdbb0b418fdfd1d458c" dependencies = [ + "aarch64-cpu 10.0.0", + "bitflags 2.10.0", "aarch64-cpu 11.2.0", "bitflags 2.11.0", "enum_dispatch", @@ -251,14 +253,14 @@ dependencies = [ [[package]] name = "arm_vcpu" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8581cf4d84a33f95aa43d39c0a25cabeeaddd65c97a790a0830e37da6e5d871" +checksum = "979230a9de461189f361c5a41a01006b4e943dcf9ebbac1c1444fb6c29fdbae2" dependencies = [ - "aarch64-cpu 10.0.0", + "aarch64-cpu 11.2.0", "axaddrspace", "axdevice_base", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvcpu", "axvisor_api", "log", @@ -269,20 +271,20 @@ dependencies = [ [[package]] name = "arm_vgic" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e2c4d90852cad20bbe1e5ee6e6d1b05468b98787a8344ffea58537eb54f375" +checksum = "49c287b9ceddf2a9f36662df520a85e2fca93a194d303d98d50727c4b19647fa" dependencies = [ - "aarch64-cpu 10.0.0", + "aarch64-cpu 11.2.0", "aarch64_sysreg", "axaddrspace", "axdevice_base", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvisor_api", "bitmaps", "log", "memory_addr", - "spin 0.9.8", + "spin 0.10.0", "tock-registers 0.10.1", ] @@ -345,11 +347,11 @@ dependencies = [ [[package]] name = "axaddrspace" -version = "0.1.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91962ea80ef137c2986b6802d664900e73aa7a014272c13dd9172cc948d5c94e" +checksum = "8b2dffa605d03eb184604fb7fcc15f2e641cf21b7a17b8f71e23b22f5c04b7be" dependencies = [ - "axerrno 0.1.2", + "axerrno 0.2.2", "bit_field", "bitflags 2.11.0", "cfg-if", @@ -358,8 +360,8 @@ dependencies = [ "memory_addr", "memory_set", "numeric-enum-macro", - "page_table_entry", - "page_table_multiarch", + "page_table_entry 0.6.1", + "page_table_multiarch 0.6.1", "x86", ] @@ -439,7 +441,7 @@ version = "0.3.0-preview.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361edfc761188b19fb3d906b0b155942a6290068ee88d42f3b1f0ce31dcd099e" dependencies = [ - "aarch64-cpu 11.2.0", + "aarch64-cpu 10.0.0", "axbacktrace", "cfg-if", "lazyinit", @@ -447,10 +449,10 @@ dependencies = [ "log", "loongArch64", "memory_addr", - "page_table_entry", - "page_table_multiarch", + "page_table_entry 0.5.7", + "page_table_multiarch 0.5.7", "percpu", - "riscv 0.16.0", + "riscv 0.14.0", "static_assertions", "tock-registers 0.10.1", "x86", @@ -459,33 +461,32 @@ dependencies = [ [[package]] name = "axdevice" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473e2bedf3a04bede7ab6e05909d56f8aed538c56507ce172aaaf0d14dc3be36" +checksum = "55bcbe9825eecc55421eb205511a0d359f0c83141a4df53f9d3c2824b515fbba" dependencies = [ "arm_vgic", "axaddrspace", "axdevice_base", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvmconfig", "cfg-if", "log", "memory_addr", "range-alloc-arceos", "riscv_vplic", - "spin 0.9.8", + "spin 0.10.0", ] [[package]] name = "axdevice_base" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2707beb1e7bb6557406d77f3968a9ed7ec3d0476691022eafa550c266ec5c9" +checksum = "3f466dbb1dcf24f0ad76f737b9b65425a1bdaef30daeff938c9d69d808eb1805" dependencies = [ "axaddrspace", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvmconfig", - "memory_addr", "serde", ] @@ -506,6 +507,7 @@ dependencies = [ "axplat-dyn", "cfg-if", "crate_interface 0.1.4", + "dma-api 0.5.2", "log", "smallvec", ] @@ -587,7 +589,7 @@ dependencies = [ "axbacktrace", "axconfig", "axdriver", - "axfs", + "axfs 0.2.0", "axhal", "axlog", "axruntime", @@ -610,6 +612,7 @@ dependencies = [ "axfs_vfs", "axio", "cap_access", + "fatfs 0.4.0 (git+https://github.com/Josen-B/rust-fatfs.git?rev=41122ef)", "lazyinit", "log", "rsext4", @@ -617,14 +620,24 @@ dependencies = [ ] [[package]] -name = "axfs_devfs" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b87ae981272ca8d5d8f106a4452c63f4b5ac36e17ee8f848ee1b250538b9f8" +name = "axfs" +version = "0.2.0" +source = "git+https://github.com/arceos-org/arceos.git?tag=dev-251216#16096568f5ae6ad2d687eff2927a4cb69cef8133" dependencies = [ + "axdriver", + "axdriver_block 0.1.2 (git+https://github.com/arceos-org/axdriver_crates.git?tag=dev-v01)", + "axerrno 0.1.2", + "axfs_devfs", + "axfs_ramfs", "axfs_vfs", + "axio", + "axsync", + "cap_access", + "cfg-if", + "fatfs 0.4.0 (git+https://github.com/rafalh/rust-fatfs?rev=4eccb50)", + "lazyinit", "log", - "spin 0.9.8", + "scope-local", ] [[package]] @@ -662,7 +675,7 @@ dependencies = [ "axplat-aarch64-qemu-virt", "axplat-dyn", "axplat-loongarch64-qemu-virt", - "axplat-riscv64-qemu-virt", + "axplat-riscv64-qemu-virt 0.3.0 (git+https://github.com/arceos-org/axplat_crates.git?tag=dev-v03)", "axplat-x86-pc", "cfg-if", "fdt-parser", @@ -671,7 +684,7 @@ dependencies = [ "linkme", "log", "memory_addr", - "page_table_multiarch", + "page_table_multiarch 0.5.7", "percpu", "spin 0.10.0", ] @@ -745,21 +758,49 @@ dependencies = [ "axplat-macros", "bitflags 2.11.0", "const-str", - "crate_interface 0.3.0", + "crate_interface 0.1.4", "handler_table", "kspin", "memory_addr", "percpu", ] +[[package]] +name = "axplat-aarch64-dyn" +version = "0.4.0" +source = "git+https://github.com/arceos-hypervisor/axplat-aarch64-dyn.git?tag=v0.4.0#05d5acd43d925807496255a9b9e1aa2d272bb591" +dependencies = [ + "aarch64-cpu 10.0.0", + "aarch64-cpu-ext", + "any-uart", + "arm-gic-driver", + "axconfig-macros", + "axcpu", + "axplat", + "fdt-parser", + "heapless 0.8.0", + "lazyinit", + "log", + "memory_addr", + "page_table_entry 0.5.7", + "paste", + "percpu", + "rdif-intc", + "rdrive", + "serde", + "somehal", + "spin 0.10.0", + "toml 0.8.23", +] + [[package]] name = "axplat-aarch64-peripherals" version = "0.3.1-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a744097da129e66068e4fff6758726c98bf329a7182dcc65712ac80daed581ed" dependencies = [ - "aarch64-cpu 11.2.0", - "arm-gic-driver 0.16.4", + "aarch64-cpu 10.0.0", + "arm-gic-driver", "arm_pl011", "arm_pl031", "axcpu", @@ -768,6 +809,7 @@ dependencies = [ "kspin", "lazyinit", "log", + "page_table_entry 0.5.7", "spin 0.10.0", ] @@ -782,7 +824,7 @@ dependencies = [ "axplat", "axplat-aarch64-peripherals", "log", - "page_table_entry", + "page_table_entry 0.5.7", ] [[package]] @@ -826,7 +868,7 @@ dependencies = [ "lazyinit", "log", "loongArch64", - "page_table_entry", + "page_table_entry 0.5.7", "uart_16550", ] @@ -843,17 +885,35 @@ dependencies = [ [[package]] name = "axplat-riscv64-qemu-virt" -version = "0.3.1-pre.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f91aff22afadd24807e34fb94fe4d0d2c8c5b86fb89dd6ff87a8093f812518" +version = "0.3.0" dependencies = [ "axconfig-macros", "axcpu", "axplat", + "axvisor_api", + "crate_interface 0.3.0", "kspin", "lazyinit", "log", - "riscv 0.16.0", + "riscv 0.14.0", + "riscv_goldfish", + "riscv_plic", + "sbi-rt", + "uart_16550", +] + +[[package]] +name = "axplat-riscv64-qemu-virt" +version = "0.3.0" +source = "git+https://github.com/arceos-org/axplat_crates.git?tag=dev-v03#0df0713b1c20eafaeebdc6b0e194b2985e857949" +dependencies = [ + "axconfig-macros", + "axcpu", + "axplat", + "kspin", + "lazyinit", + "log", + "riscv 0.14.0", "riscv_plic", "sbi-rt", "uart_16550", @@ -928,12 +988,16 @@ dependencies = [ "axbacktrace", "axconfig", "axdriver", - "axfs", + "axerrno 0.2.2", + "axfs 0.1.0", "axhal", "axklib", "axlog", "axmm", "axplat", + "axplat-aarch64-dyn", + "axplat-riscv64-qemu-virt 0.3.0", + "axplat-x86-qemu-q35", "axtask", "cfg-if", "chrono", @@ -1060,12 +1124,12 @@ dependencies = [ [[package]] name = "axvcpu" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70880a87fffe8087719ad2e7aa09da482db88a65d123dc9170297b7e2a162fb5" +checksum = "506c3ab0ce353e76d3279927b88a43ee0effd4368ce86e8bc72a0ee9430e0709" dependencies = [ "axaddrspace", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvisor_api", "memory_addr", "percpu", @@ -1082,8 +1146,11 @@ dependencies = [ "axconfig", "axdevice", "axdevice_base", + "axdriver", "axerrno 0.2.2", "axhvc", + "axplat-riscv64-qemu-virt 0.3.0", + "axruntime", "axklib", "axplat-x86-qemu-q35", "axstd", @@ -1099,7 +1166,8 @@ dependencies = [ "clap", "colored", "cpumask", - "crate_interface 0.1.4", + "crate_interface 0.3.0", + "driver", "extern-trait", "fdt-parser", "flate2", @@ -1111,10 +1179,8 @@ dependencies = [ "lazyinit", "log", "memory_addr", - "ostool", - "page_table_entry", - "page_table_multiarch", - "pcie 0.5.0", + "page_table_entry 0.6.1", + "page_table_multiarch 0.6.1", "percpu", "phytium-mci", "prettyplease", @@ -1124,19 +1190,10 @@ dependencies = [ "rdif-clk", "rdif-intc", "rdrive", - "regex", - "reqwest 0.13.2", - "rk3568_clk", - "rk3588-clk", - "rockchip-pm", - "schemars", - "sdmmc", - "serde", - "serde_json", - "sha2", - "spin 0.9.8", - "syn 2.0.117", - "tar", + "riscv_vcpu", + "riscv_vplic", + "spin 0.10.0", + "syn 2.0.111", "timer_list", "tokio", "toml", @@ -1144,21 +1201,22 @@ dependencies = [ [[package]] name = "axvisor_api" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7233b2a1338dc06a80e2779b572b4df02007ea128ef7b235b66fc3eeac0ca6" +checksum = "7959b2dd8afbac2a0cda189986df6ceb753a92e985c28ce2c279cf432cbe2dfc" dependencies = [ "axaddrspace", "axvisor_api_proc", - "crate_interface 0.1.4", + "cpumask", + "crate_interface 0.3.0", "memory_addr", ] [[package]] name = "axvisor_api_proc" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a64eb4410ae8357ac8c01c2fb201e57d7aeeb5436ed4d0f5774bfa11cc5902" +checksum = "f5351791fec23f5545518f88d4d8a134c564085a6f37ed6953bbd4f35d4f32c7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1168,9 +1226,9 @@ dependencies = [ [[package]] name = "axvm" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c13dc01a73107817fa04f8f2cad019eaee992541713d7064fd2da855502c6d" +checksum = "22f6406a71e7af560b7d544fb697f3071e045d304a20d8525502b5a906dbbaab" dependencies = [ "arm_vcpu", "arm_vgic", @@ -1179,16 +1237,17 @@ dependencies = [ "axdevice_base", "axerrno 0.2.2", "axvcpu", + "axvisor_api", "axvmconfig", "cfg-if", "cpumask", "log", "memory_addr", - "page_table_entry", - "page_table_multiarch", + "page_table_entry 0.6.1", + "page_table_multiarch 0.6.1", "percpu", "riscv_vcpu", - "spin 0.9.8", + "spin 0.10.0", "x86_vcpu", ] @@ -2085,6 +2144,23 @@ dependencies = [ "litrs", ] +[[package]] +name = "driver" +version = "0.1.0" +dependencies = [ + "axklib", + "log", + "phytium-mci", + "rdif-block", + "rdif-clk", + "rdrive", + "rk3568_clk", + "rk3588-clk", + "rockchip-pm", + "sdmmc", + "spin 0.10.0", +] + [[package]] name = "dunce" version = "1.0.5" @@ -2290,6 +2366,15 @@ dependencies = [ "log", ] +[[package]] +name = "fatfs" +version = "0.4.0" +source = "git+https://github.com/rafalh/rust-fatfs?rev=4eccb50#4eccb50d011146fbed20e133d33b22f3c27292e7" +dependencies = [ + "bitflags 2.10.0", + "log", +] + [[package]] name = "fdt-parser" version = "0.4.18" @@ -3606,10 +3691,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42c5b75d5d9bdbee44c827b0dd2766fa3d478a76b9c6735419228089d1b24536" dependencies = [ "arrayvec", - "axerrno 0.1.2", "log", "memory_addr", - "page_table_entry", + "page_table_entry 0.6.1", "riscv 0.16.0", "x86", ] @@ -3731,6 +3815,51 @@ dependencies = [ "tock-registers 0.9.0", ] +[[package]] +name = "pie-boot-if" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d979b0d1208dd8a57c5adb7d3c4e07bf15cbea3840123e864f6bfcb655c5e05" +dependencies = [ + "heapless 0.8.0", +] + +[[package]] +name = "pie-boot-loader-aarch64" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de8836eb8759cd65e70c73dc0f519345d8a734284e8e4cfc5889a6e445af9f09" +dependencies = [ + "aarch64-cpu 10.0.0", + "aarch64-cpu-ext", + "any-uart", + "bitflags 2.10.0", + "fdt-parser", + "kasm-aarch64", + "kdef-pgtable", + "log", + "num-align", + "page-table-generic", + "pie-boot-if", + "prettyplease", + "quote", + "spin 0.10.0", + "syn 2.0.111", + "thiserror 2.0.17", +] + +[[package]] +name = "pie-boot-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513f5ca7603771d7524bfb7e6ba8dded83d2e8ac02d46f15815e0c1144bca566" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -4382,7 +4511,6 @@ dependencies = [ "critical-section", "embedded-hal", "paste", - "riscv-macros 0.4.0", "riscv-types", ] @@ -4392,19 +4520,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b59d645e392e041ad18f5e529ed13242d8405c66bb192f59703ea2137017d0" -[[package]] -name = "riscv-h" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cffa652689d01c5f7033abe105e69f4d57ac85bf7e17da688bab10e4b9d3a2d8" -dependencies = [ - "bare-metal", - "bit_field", - "bitflags 2.11.0", - "log", - "riscv 0.14.0", -] - [[package]] name = "riscv-h" version = "0.2.0" @@ -4452,6 +4567,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3f2ad9f15a07f4a0e1677124f9120ce7e83ab7e1ca7186af0ca9da529b62e80" +[[package]] +name = "riscv_goldfish" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07aac72f95e774476db82916d79f2d303191310393830573c1ab5c821b21660a" + [[package]] name = "riscv_plic" version = "0.2.0" @@ -4463,29 +4584,45 @@ dependencies = [ [[package]] name = "riscv_vcpu" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6122b26f3d5920206f22b871fd13d79f5b23e570c7860f345d8736528dacc4c" +checksum = "8f7d192465c7a3e2f674c56d3e49cfeb00f84d0616137cbecb8aacb250e40c53" dependencies = [ "axaddrspace", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvcpu", "axvisor_api", "bit_field", "bitflags 2.11.0", "cfg-if", - "crate_interface 0.1.4", + "crate_interface 0.3.0", "log", "memoffset", "memory_addr", - "page_table_entry", + "page_table_entry 0.6.1", "riscv 0.14.0", "riscv-decode", "riscv-h 0.2.0", "rustsbi", "sbi-rt", "sbi-spec", - "tock-registers 0.9.0", + "tock-registers 0.10.1", +] + +[[package]] +name = "riscv_vplic" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec84bba7d814f072afdd11a61c64ad55bedaeb17937a78bb6b9cec44b63a70fb" +dependencies = [ + "axaddrspace", + "axdevice_base", + "axerrno 0.2.2", + "axvisor_api", + "bitmaps", + "log", + "riscv-h", + "spin 0.10.0", ] [[package]] @@ -4830,6 +4967,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "scope-local" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a7d5ed5013e6436fcd78f2bcd3892a6286ef9ce6c9b61504d4c4a08d6a40eab" +dependencies = [ + "percpu", + "spin 0.10.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -5182,10 +5329,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df2e441db2f693b803ee5fdf85b89bcc1830c83ae483406d4f0bb74cf90473a6" dependencies = [ - "aarch64-cpu 11.2.0", - "anyhow", - "arm-gic-driver 0.17.0", - "kernutil", + "aarch64-cpu 10.0.0", + "aarch64-cpu-ext", + "any-uart", + "bindeps-simple", + "fdt-parser", + "futures", + "heapless 0.8.0", + "kasm-aarch64", + "kdef-pgtable", "log", "mmio-api", "page-table-generic", @@ -6575,26 +6727,26 @@ dependencies = [ [[package]] name = "x86_vcpu" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b71adc527803929792ea1af4a2cd7c264c9cd3dd0096b03f9bc959505f73a" +checksum = "906f6ead2156dde21b712f0eb654b620d1c2652e62b6b0731a7807a565454692" dependencies = [ "axaddrspace", "axdevice_base", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvcpu", "axvisor_api", "bit_field", "bitflags 2.11.0", "cfg-if", - "crate_interface 0.1.4", + "crate_interface 0.3.0", "log", "memory_addr", "numeric-enum-macro", - "page_table_entry", + "page_table_entry 0.6.1", "paste", "raw-cpuid 11.6.0", - "spin 0.9.8", + "spin 0.10.0", "x86", "x86_64", "x86_vlapic", @@ -6602,13 +6754,13 @@ dependencies = [ [[package]] name = "x86_vlapic" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809257bd2252fc337f3b494ae9230e4600bfa4e7d3f2478a0dd794e16849040d" +checksum = "73364dacf1435c64e3395567405311456c3087f7bb4852904332e0fa1379eb65" dependencies = [ "axaddrspace", "axdevice_base", - "axerrno 0.1.2", + "axerrno 0.2.2", "axvisor_api", "bit", "log", diff --git a/Cargo.toml b/Cargo.toml index beb33782..d64ee8d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,39 +31,17 @@ lto = true [[bin]] name = "xtask" path = "xtask/src/main.rs" -required-features = ["xtask"] [features] default = [] -ept-level-4 = ["axaddrspace/4-level-ept"] +ept-level-4 = [] fs = ["axstd/fs"] dyn-plat = ["axstd/plat-dyn"] # Driver features (from former driver crate) -rk3568-clk = ["dep:rk3568_clk"] rk3588-clk = ["dep:rk3588-clk"] sdmmc = ["dep:sdmmc"] rockchip-pm = ["dep:rockchip-pm"] phytium-blk = ["dep:phytium-mci"] -xtask = [ - "dep:anyhow", - "dep:axvmconfig", - "dep:cargo_metadata", - "dep:chrono", - "dep:clap", - "dep:colored", - "dep:flate2", - "dep:jkconfig", - "dep:ostool", - "dep:regex", - "dep:reqwest", - "dep:schemars", - "dep:serde", - "dep:serde_json", - "dep:sha2", - "dep:tar", - "dep:tokio", - "dep:toml", -] [target.'cfg(not(any(windows, unix)))'.dependencies] bitflags = "2.2" @@ -74,7 +52,7 @@ kspin = "0.1" lazy_static = {version = "1.5", default-features = false, features = ["spin_no_std"]} lazyinit = "0.2" log = "0.4" -spin = "0.9" +spin = "0.10" timer_list = "0.1.0" hashbrown = "0.14" @@ -90,21 +68,21 @@ axstd = { version = "=0.3.0-preview.3", features = [ ]} # System dependent modules provided by ArceOS-Hypervisor (bare-metal only) -axaddrspace = "0.1.5" +axaddrspace = "0.3.0" axhvc = "0.2.0" # axruntime = { version = "=0.3.0-preview.1", features = ["alloc", "irq", "paging", "smp", "multitask"] } -axvcpu = "0.2.2" -axvm = "0.2.1" -axdevice = "0.2.1" -axdevice_base = "0.2.1" -axvisor_api = "0.1.0" +axvcpu = "0.3.0" +axvm = "0.3.0" +axdevice = "0.2.2" +axdevice_base = "0.2.2" +axvisor_api = "0.3.0" # System independent crates provided by ArceOS axerrno = "0.2.2" axklib = "0.3.0" # axcpu = { version = "0.3.0-preview.8", features = ["arm-el2"] } byte-unit = {version = "5", default-features = false, features = ["byte"]} -crate_interface = "0.1.4" +crate_interface = "0.3" extern-trait = "0.4" fdt-parser = "0.4" memory_addr = "0.4.1" @@ -120,16 +98,11 @@ rd-block = "0.1" pcie = "0.5.0" # Optional driver dependencies -rk3568_clk = { version = "0.1", optional = true } sdmmc = { version = "0.1", default-features = false, features = ["pio"], optional = true } rk3588-clk = { version = "0.1", optional = true } rockchip-pm = { version = "0.4", optional = true } phytium-mci = { version = "0.1", default-features = false, features = ["pio"], optional = true } -[target.'cfg(target_arch = "aarch64")'.dependencies] -aarch64-cpu-ext = "0.1" -arm-gic-driver = {version = "0.17", features = ["rdif"]} - [target.'cfg(target_arch = "x86_64")'.dependencies] axplat-x86-qemu-q35 = { version = "0.2.0", default-features = false, features = [ "reboot-on-system-off", @@ -138,27 +111,34 @@ axplat-x86-qemu-q35 = { version = "0.2.0", default-features = false, features = ] } axconfig = { version = "=0.3.0-preview.3", features = ["plat-dyn"] } -# xtask dependencies (only used when xtask feature is enabled) +[target.'cfg(target_arch = "aarch64")'.dependencies] +aarch64-cpu-ext = "0.1" +arm-gic-driver = {version = "0.17", features = ["rdif"]} + +[target.'cfg(target_arch = "riscv64")'.dependencies] +axplat-riscv64-qemu-virt = "0.3.1-pre.6" + +# xtask dependencies (only used on host platforms) [target.'cfg(any(windows, unix))'.dependencies] -anyhow = { version = "1.0", optional = true } -cargo_metadata = { version = "0.23", optional = true } -chrono = { version = "0.4", features = ["serde"], optional = true } -clap = {version = "4.4", features = ["derive"], optional = true } -colored = { version = "3", optional = true } -flate2 = { version = "1.0", optional = true } -jkconfig = { version = "0.1", optional = true } -ostool = { version = "0.8.4", optional = true } -regex = { version = "1.12", optional = true } -reqwest = { version = "0.13", optional = true } -schemars = {version = "1", features = ["derive"], optional = true } -serde = {version = "1.0", features = ["derive"], optional = true } -serde_json = { version = "1", optional = true } -sha2 = { version = "0.10", optional = true } -tar = { version = "0.4", optional = true } -tokio = {version = "1", features = ["full"], optional = true } -toml = { version = "0.9", optional = true } +anyhow = { version = "1.0" } +cargo_metadata = { version = "0.23" } +chrono = { version = "0.4", features = ["serde"] } +clap = {version = "4.4", features = ["derive"] } +colored = { version = "3" } +flate2 = { version = "1.0" } +jkconfig = { version = "0.1" } +ostool = { version = "0.8.4" } +regex = { version = "1.12" } +reqwest = { version = "0.13" } +schemars = {version = "1", features = ["derive"] } +serde = {version = "1.0", features = ["derive"] } +serde_json = { version = "1" } +sha2 = { version = "0.10" } +tar = { version = "0.4" } +tokio = {version = "1", features = ["full"] } +toml = { version = "0.9" } -axvmconfig = { version = "0.2", features = ["std"], optional = true } +axvmconfig = { version = "0.2.2", features = ["std"] } [build-dependencies] axconfig = "=0.3.0-preview.3" diff --git a/build.rs b/build.rs index bd5125d0..ff8acb01 100644 --- a/build.rs +++ b/build.rs @@ -260,6 +260,8 @@ fn main() -> anyhow::Result<()> { "aarch64-generic".to_string() } else if arch == "x86_64" { "x86-qemu-q35".to_string() + } else if arch == "riscv64" { + "riscv64-qemu-virt".to_string() } else { "dummy".to_string() }; diff --git a/configs/board/orangepi-5-plus.toml b/configs/board/orangepi-5-plus.toml index 21559ce5..465a3b29 100644 --- a/configs/board/orangepi-5-plus.toml +++ b/configs/board/orangepi-5-plus.toml @@ -1,4 +1,7 @@ -cargo_args = [] +cargo_args = [ + "--config", + 'target.aarch64-unknown-none-softfloat.rustflags = ["-Crelocation-model=pic", "-Clink-args=-pie", "-Clink-args=-znostart-stop-gc", "-Clink-args=-Taxplat.x"]', +] features = [ # "ept-level-4", "dyn-plat", diff --git a/configs/board/phytiumpi.toml b/configs/board/phytiumpi.toml index 2fc970ca..d55d7489 100644 --- a/configs/board/phytiumpi.toml +++ b/configs/board/phytiumpi.toml @@ -1,4 +1,7 @@ -cargo_args = [] +cargo_args = [ + "--config", + 'target.aarch64-unknown-none-softfloat.rustflags = ["-Crelocation-model=pic", "-Clink-args=-pie", "-Clink-args=-znostart-stop-gc", "-Clink-args=-Taxplat.x"]', +] features = [ # "ept-level-4", "dyn-plat", diff --git a/configs/board/qemu-aarch64.toml b/configs/board/qemu-aarch64.toml index c379cc79..77eeb678 100644 --- a/configs/board/qemu-aarch64.toml +++ b/configs/board/qemu-aarch64.toml @@ -1,4 +1,11 @@ -cargo_args = [] +cargo_args = [ + "--config", + 'target.aarch64-unknown-none-softfloat.rustflags = ["-Crelocation-model=pic", "-Clink-args=-pie", "-Clink-args=-znostart-stop-gc", "-Clink-args=-Taxplat.x"]', +] +# cargo_args = [ +# "--config", +# 'target.aarch64-unknown-none-softfloat.rustflags = ["-Clink-args=-Taxplat.x"]', +# ] features = [ "ept-level-4", "axstd/bus-mmio", @@ -7,4 +14,4 @@ features = [ log = "Info" target = "aarch64-unknown-none-softfloat" to_bin = true -vm_configs = [] \ No newline at end of file +vm_configs = [] diff --git a/configs/board/qemu-riscv64.toml b/configs/board/qemu-riscv64.toml new file mode 100644 index 00000000..62a82d79 --- /dev/null +++ b/configs/board/qemu-riscv64.toml @@ -0,0 +1,12 @@ +cargo_args = [] +features = [ + "axstd/myplat", + "axstd/bus-mmio", + "ept-level-4", + # "fs", +] +log = "Info" +target = "riscv64gc-unknown-none-elf" +to_bin = true +vm_configs = [] +smp = 4 diff --git a/configs/board/roc-rk3568-pc.toml b/configs/board/roc-rk3568-pc.toml index 5ccf6633..9a40e555 100644 --- a/configs/board/roc-rk3568-pc.toml +++ b/configs/board/roc-rk3568-pc.toml @@ -1,4 +1,7 @@ -cargo_args = [] +cargo_args = [ + "--config", + 'target.aarch64-unknown-none-softfloat.rustflags = ["-Crelocation-model=pic", "-Clink-args=-pie", "-Clink-args=-znostart-stop-gc", "-Clink-args=-Taxplat.x"]', +] features = [ # "ept-level-4", "dyn-plat", diff --git a/configs/vms/arceos-riscv64-qemu-smp1.toml b/configs/vms/arceos-riscv64-qemu-smp1.toml new file mode 100644 index 00000000..ff4a5ca1 --- /dev/null +++ b/configs/vms/arceos-riscv64-qemu-smp1.toml @@ -0,0 +1,72 @@ +# Vm base info configs +# +[base] +# Guest vm id. +id = 1 +# Guest vm name. +name = "arceos-qemu" +# Virtualization type. +vm_type = 1 +# The number of virtual CPUs. +cpu_num = 1 +# Guest vm physical cpu ids. +phys_cpu_ids = [0] + +# +# Vm kernel configs +# +[kernel] +# The entry point of the kernel image. +entry_point = 0x8020_0000 +# The location of image: "memory" | "fs". +# load from memory. +image_location = "memory" +# The file path of the kernel image. +kernel_path = "/path/tmp/images/helloworld_riscv64-qemu-virt.bin" +# The load address of the kernel image. +kernel_load_addr = 0x8020_0000 +# The file path of the device tree blob (DTB). +#dtb_path = "path/aarch64-qemu-gicv3.dtb" +# The load address of the device tree blob (DTB). +dtb_load_addr = 0x8220_0000 + +## The file path of the ramdisk image. +# ramdisk_path = "" +## The load address of the ramdisk image. +# ramdisk_load_addr = 0 +## The path of the disk image. +# disk_path = "disk.img" + +# Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). +# For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. +memory_regions = [ + [0x8000_0000, 0x800_0000, 0x7, 0], # System RAM 1G MAP_ALLOC +] + +# +# Device specifications +# +[devices] +# Pass-through devices. +passthrough_devices = [ +] + +# Passthrough addresses. +# Base-GPA Length. +passthrough_addresses = [ + #[0x28041000, 0x100_0000] +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ +] + +# Emu_devices. +# Name Base-Ipa Ipa_len Alloc-Irq Emu-Type EmuConfig. +emu_devices = [ + # ["gppt-gicd", 0x0800_0000, 0x1_0000, 0, 0x21, []], + # ["gppt-gicr", 0x080a_0000, 0x2_0000, 0, 0x20, [1, 0x2_0000, 0]], # 1 vcpu, stride 0x20000, starts with pcpu 0 + # ["gppt-gits", 0x0808_0000, 0x2_0000, 0, 0x22, [0x0808_0000]], # host_gits_base +] + +interrupt_mode = "passthrough" diff --git a/configs/vms/linux-riscv64-qemu-smp1.dts b/configs/vms/linux-riscv64-qemu-smp1.dts new file mode 100644 index 00000000..7a09d097 --- /dev/null +++ b/configs/vms/linux-riscv64-qemu-smp1.dts @@ -0,0 +1,132 @@ +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "riscv-virtio"; + model = "riscv-virtio,qemu"; + + memory@90000000 { + device_type = "memory"; + reg = <0x00 0x90000000 0x00 0x40000000>; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <0x989680>; + + cpu@0 { + phandle = <0x07>; + device_type = "cpu"; + reg = <0x00>; + status = "okay"; + compatible = "riscv"; + riscv,cbop-block-size = <0x40>; + riscv,cboz-block-size = <0x40>; + riscv,cbom-block-size = <0x40>; + riscv,isa-extensions = "i\0m\0a\0f\0d\0c"; + riscv,isa-base = "rv64i"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv39"; + + interrupt-controller { + #interrupt-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x08>; + }; + }; + }; + + aliases { + serial0 = "/soc/serial@10000000"; + }; + + chosen { + bootargs = "earlycon=sbi console=ttyS0,115200 init=/init root=/dev/vda rw"; + stdout-path = "/soc/serial@10000000"; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + serial@10000000 { + interrupts = <0x0a>; + interrupt-parent = <0x09>; + clock-frequency = "\08@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + + plic@c000000 { + phandle = <0x09>; + riscv,ndev = <0x5f>; + reg = <0x00 0xc000000 0x00 0x600000>; + interrupts-extended = <0x08 0x0b 0x08 0x09>; + interrupt-controller; + compatible = "sifive,plic-1.0.0\0riscv,plic0"; + #address-cells = <0x00>; + #interrupt-cells = <0x01>; + }; + + virtio_mmio@10008000 { + interrupts = <0x08>; + interrupt-parent = <0x09>; + reg = <0x00 0x10008000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10007000 { + interrupts = <0x07>; + interrupt-parent = <0x09>; + reg = <0x00 0x10007000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10006000 { + interrupts = <0x06>; + interrupt-parent = <0x09>; + reg = <0x00 0x10006000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10005000 { + interrupts = <0x05>; + interrupt-parent = <0x09>; + reg = <0x00 0x10005000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10004000 { + interrupts = <0x04>; + interrupt-parent = <0x09>; + reg = <0x00 0x10004000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10003000 { + interrupts = <0x03>; + interrupt-parent = <0x09>; + reg = <0x00 0x10003000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10002000 { + interrupts = <0x02>; + interrupt-parent = <0x09>; + reg = <0x00 0x10002000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10001000 { + interrupts = <0x01>; + interrupt-parent = <0x09>; + reg = <0x00 0x10001000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + }; +}; diff --git a/configs/vms/linux-riscv64-qemu-smp1.toml b/configs/vms/linux-riscv64-qemu-smp1.toml new file mode 100644 index 00000000..7aeacebb --- /dev/null +++ b/configs/vms/linux-riscv64-qemu-smp1.toml @@ -0,0 +1,67 @@ +# Vm base info configs +# +[base] +# Guest vm id. +id = 1 +# Guest vm name. +name = "linux-qemu" +# Virtualization type. +vm_type = 1 +# The number of virtual CPUs. +cpu_num = 1 +# Guest vm physical cpu sets. +phys_cpu_ids = [0] + +# +# Vm kernel configs +# +[kernel] +# The entry point of the kernel image. +entry_point = 0x9000_0000 +# The location of image: "memory" | "fs". +# load from memory. +image_location = "memory" +# The file path of the kernel image. +# kernel_path = "linux-6.6.62.bin" +kernel_path = "/path/tmp/images/qemu_riscv64_linux/qemu-riscv64" +# The load address of the kernel image. +kernel_load_addr = 0x9000_0000 +# The file path of the device tree blob (DTB). +dtb_path = "/path/tmp/configs/linux-riscv64-qemu-smp1.dtb" +# The load address of the device tree blob (DTB). +dtb_load_addr = 0x9300_0000 + +# Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). +# For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. +memory_regions = [ + [0x9000_0000, 0x4000_0000, 0x7, 2], # System RAM 1G MAP_IDENTICAL +] + +# +# Device specifications +# +[devices] +# Pass-through devices. +# Name Base-Ipa Base-Pa Length Alloc-Irq. +passthrough_devices = [ + # ["/soc/serial@10000000", 0x1000_0000, 0x1000_0000, 0x1000, 33], +] + +# Passthrough addresses. +# Base-GPA Length. +passthrough_addresses = [ + [0x1000_0000, 0x1000], # uart + [0x1000_1000, 0x8000], # virtio-mmio +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ +] + +# Emu_devices. +# Name Base-Ipa Ipa_len Alloc-Irq Emu-Type EmuConfig. +emu_devices = [ + ["plic", 0x0c00_0000, 0x60_0000, 0, 0x30, [2]], # [context_num] +] + +interrupt_mode = "passthrough" diff --git a/configs/vms/nimbos-aarch64-qemu-smp1.toml b/configs/vms/nimbos-aarch64-qemu-smp1.toml index 17dac0d4..e280c206 100644 --- a/configs/vms/nimbos-aarch64-qemu-smp1.toml +++ b/configs/vms/nimbos-aarch64-qemu-smp1.toml @@ -73,6 +73,7 @@ passthrough_devices = [ # Base-GPA Length. passthrough_addresses = [ #[0x28041000, 0x100_0000] + [0x0800_0000, 0x100_0000] ] # Devices that are not desired to be passed through to the guest diff --git a/platform/riscv64-qemu-virt/Cargo.toml b/platform/riscv64-qemu-virt/Cargo.toml new file mode 100644 index 00000000..869095be --- /dev/null +++ b/platform/riscv64-qemu-virt/Cargo.toml @@ -0,0 +1,33 @@ +[package] +edition = "2024" +name = "axplat-riscv64-qemu-virt" +version = "0.3.0" + +[features] +default = [ + "irq", + "smp", +] +fp-simd = ["axcpu/fp-simd"] +irq = ["axplat/irq"] +rtc = ["riscv_goldfish"] +smp = ["axplat/smp"] + +[dependencies] +kspin = "0.1" +lazyinit = "0.2" +log = "0.4" +riscv = "0.14.0" +riscv_goldfish = { version = "0.1", optional = true } +riscv_plic = "0.2" +sbi-rt = { version = "0.0.3", features = ["legacy"] } +uart_16550 = "0.4.0" + +axconfig-macros = "0.2" +axcpu = { version = "0.3.0-preview.8", features = ["arm-el2"] } +axplat = "0.3.1-pre.6" +axvisor_api = "0.3" +crate_interface = "0.3" + +[package.metadata.docs.rs] +targets = ["riscv64gc-unknown-none-elf"] diff --git a/platform/riscv64-qemu-virt/axconfig.toml b/platform/riscv64-qemu-virt/axconfig.toml new file mode 100644 index 00000000..581a4a74 --- /dev/null +++ b/platform/riscv64-qemu-virt/axconfig.toml @@ -0,0 +1,105 @@ +# Architecture identifier. +arch = "riscv64" # str +# Platform identifier. +platform = "riscv64-qemu-virt" # str +# Platform package. +package = "axplat-riscv64-qemu-virt" # str + +# +# Platform configs +# +[plat] +# Number of CPUs. +cpu-num = 4 # uint +# Base address of the whole physical memory. +phys-memory-base = 0x8000_0000 # uint +# Size of the whole physical memory. (8GB) +phys-memory-size = 0x1_0000_0000 # uint +# Base physical address of the kernel image. +kernel-base-paddr = 0x8020_0000 # uint +# Base virtual address of the kernel image. +kernel-base-vaddr = "0xffff_ffc0_8020_0000" # uint +# Linear mapping offset, for quick conversions between physical and virtual +# addresses. +phys-virt-offset = "0xffff_ffc0_0000_0000" # uint +# Offset of bus address and phys address. some boards, the bus address is +# different from the physical address. +phys-bus-offset = 0 # uint +# Kernel address space base. +kernel-aspace-base = "0xffff_ffc0_0000_0000" # uint +# Kernel address space size. +kernel-aspace-size = "0x0000_003f_ffff_f000" # uint +# Stack size on bootstrapping. (256K) +boot-stack-size = 0x40000 # uint + +# +# Device specifications +# +[devices] +# MMIO ranges with format (`base_paddr`, `size`). +mmio-ranges = [ + [0x0010_1000, 0x1000], # RTC + [0x0c00_0000, 0x21_0000], # PLIC + [0x1000_0000, 0x1000], # UART + [0x1000_1000, 0x8000], # VirtIO + [0x3000_0000, 0x1000_0000], # PCI config space + [0x4000_0000, 0x4000_0000], # PCI memory ranges (ranges 1: 32-bit MMIO space) + [0x2_7fe0_0000, 0x1000_0000] +] # [(uint, uint)] +# VirtIO MMIO ranges with format (`base_paddr`, `size`). +virtio-mmio-ranges = [ + [0x1000_1000, 0x1000], + [0x1000_2000, 0x1000], + [0x1000_3000, 0x1000], + [0x1000_4000, 0x1000], + [0x1000_5000, 0x1000], + [0x1000_6000, 0x1000], + [0x1000_7000, 0x1000], + [0x1000_8000, 0x1000], +] # [(uint, uint)] +# Base physical address of the PCIe ECAM space. +pci-ecam-base = 0x3000_0000 # uint +# End PCI bus number (`bus-range` property in device tree). +pci-bus-end = 0xff # uint +# PCI device memory ranges (`ranges` property in device tree). +pci-ranges = [ + [0x0300_0000, 0x1_0000], # PIO space + [0x4000_0000, 0x4000_0000], # 32-bit MMIO space + [0x4_0000_0000, 0x4_0000_0000], # 64-bit MMIO space +] # [(uint, uint)] + +# Timer interrupt frequency in Hz. +timer-frequency = 10_000_000 # uint +# Timer interrupt num. +timer-irq = "0x8000_0000_0000_0005" # uint +# IPI interrupt num +ipi-irq = "0x8000_0000_0000_0001" # uint + +# rtc@101000 { +# interrupts = <0x0b>; +# interrupt-parent = <0x03>; +# reg = <0x00 0x101000 0x00 0x1000>; +# compatible = "google,goldfish-rtc"; +# }; +# RTC (goldfish) Address +rtc-paddr = 0x10_1000 # uint + +# plic@c000000 { +# phandle = <0x03>; +# riscv,ndev = <0x5f>; +# reg = <0x00 0xc000000 0x00 0x600000>; +# interrupts-extended = <0x02 0x0b 0x02 0x09>; +# interrupt-controller; +# compatible = "sifive,plic-1.0.0\0riscv,plic0"; +# }; +plic-paddr = 0x0c00_0000 # uint + +# serial@10000000 { +# interrupts = <0x0a>; +# interrupt-parent = <0x03>; +# clock-frequency = "\08@"; +# reg = <0x00 0x10000000 0x00 0x100>; +# compatible = "ns16550a"; +# }; +uart-paddr = 0x1000_0000 # uint +uart-irq = 0x0a # uint \ No newline at end of file diff --git a/platform/riscv64-qemu-virt/build.rs b/platform/riscv64-qemu-virt/build.rs new file mode 100644 index 00000000..80a4c120 --- /dev/null +++ b/platform/riscv64-qemu-virt/build.rs @@ -0,0 +1,23 @@ +fn main() { + println!("cargo:rerun-if-env-changed=AXVISOR_SMP"); + println!("cargo:rerun-if-changed=linker.lds.S"); + + let mut smp = 1; + if let Ok(s) = std::env::var("AXVISOR_SMP") { + smp = s.parse::().unwrap_or(1); + } + + let ld_content = include_str!("linker.lds.S"); + let ld_content = ld_content.replace("%ARCH%", "riscv"); + let ld_content = ld_content.replace( + "%KERNEL_BASE%", + &format!("{:#x}", 0xffff_ffc0_8020_0000usize), + ); + let ld_content = ld_content.replace("%SMP%", &format!("{smp}",)); + + // target///build/axvisor-xxxx/out + let out_dir = std::env::var("OUT_DIR").unwrap(); + let out_path = std::path::Path::new(&out_dir).join("link.x"); + println!("cargo:rustc-link-search={out_dir}"); + std::fs::write(out_path, ld_content).unwrap(); +} diff --git a/platform/riscv64-qemu-virt/linker.lds.S b/platform/riscv64-qemu-virt/linker.lds.S new file mode 100644 index 00000000..439284c7 --- /dev/null +++ b/platform/riscv64-qemu-virt/linker.lds.S @@ -0,0 +1,99 @@ +OUTPUT_ARCH(%ARCH%) + +BASE_ADDRESS = %KERNEL_BASE%; +SMP = %SMP%; + +ENTRY(_start) +SECTIONS +{ + . = BASE_ADDRESS; + _skernel = .; + + .text : ALIGN(4K) { + _stext = .; + *(.text.boot) + *(.text .text.*) + . = ALIGN(4K); + _etext = .; + } + + .rodata : ALIGN(4K) { + _srodata = .; + *(.rodata .rodata.*) + *(.srodata .srodata.*) + *(.sdata2 .sdata2.*) + . = ALIGN(4K); + _erodata = .; + } + + .data : ALIGN(4K) { + _sdata = .; + *(.data.boot_page_table) + . = ALIGN(4K); + __sdriver_register = .; + KEEP(*(.driver.register*)) + __edriver_register = .; + + *(.data .data.*) + *(.sdata .sdata.*) + *(.got .got.*) + } + + .tdata : ALIGN(0x10) { + _stdata = .; + *(.tdata .tdata.*) + _etdata = .; + } + + .tbss : ALIGN(0x10) { + _stbss = .; + *(.tbss .tbss.*) + *(.tcommon) + _etbss = .; + } + + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * SMP; + } + . = _percpu_end; + + . = ALIGN(4K); + _edata = .; + + .bss : ALIGN(4K) { + boot_stack = .; + *(.bss.stack) + . = ALIGN(4K); + boot_stack_top = .; + + _sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + *(COMMON) + . = ALIGN(4K); + _ebss = .; + } + + _ekernel = .; + + /DISCARD/ : { + *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) + } +} + +SECTIONS { + linkme_IRQ : { *(linkme_IRQ) } + linkm2_IRQ : { *(linkm2_IRQ) } + linkme_PAGE_FAULT : { *(linkme_PAGE_FAULT) } + linkm2_PAGE_FAULT : { *(linkm2_PAGE_FAULT) } + linkme_SYSCALL : { *(linkme_SYSCALL) } + linkm2_SYSCALL : { *(linkm2_SYSCALL) } + axns_resource : { *(axns_resource) } +} +INSERT AFTER .tbss; diff --git a/platform/riscv64-qemu-virt/src/boot.rs b/platform/riscv64-qemu-virt/src/boot.rs new file mode 100644 index 00000000..e3a690a8 --- /dev/null +++ b/platform/riscv64-qemu-virt/src/boot.rs @@ -0,0 +1,98 @@ +use crate::config::plat::{BOOT_STACK_SIZE, PHYS_VIRT_OFFSET}; +use axplat::mem::{Aligned4K, pa}; + +#[unsafe(link_section = ".bss.stack")] +static mut BOOT_STACK: [u8; BOOT_STACK_SIZE] = [0; BOOT_STACK_SIZE]; + +#[unsafe(link_section = ".data")] +static mut BOOT_PT_SV39: Aligned4K<[u64; 512]> = Aligned4K::new([0; 512]); + +#[allow(clippy::identity_op)] // (0x0 << 10) here makes sense because it's an address +unsafe fn init_boot_page_table() { + unsafe { + // 0x0000_0000..0x4000_0000, VRWX_GAD, 1G block + BOOT_PT_SV39[0] = (0x0 << 10) | 0xef; + // 0x8000_0000..0xc000_0000, VRWX_GAD, 4G block + BOOT_PT_SV39[2] = (0x80000 << 10) | 0xef; + BOOT_PT_SV39[3] = (0xC0000 << 10) | 0xef; + BOOT_PT_SV39[4] = (0x100000 << 10) | 0xef; + BOOT_PT_SV39[5] = (0x140000 << 10) | 0xef; + // 0xffff_ffc0_0000_0000..0xffff_ffc0_4000_0000, VRWX_GAD, 1G block + BOOT_PT_SV39[0x100] = (0x0 << 10) | 0xef; + // 0xffff_ffc0_8000_0000..0xffff_ffc0_c000_0000, VRWX_GAD, 1G block + BOOT_PT_SV39[0x102] = (0x80000 << 10) | 0xef; + BOOT_PT_SV39[0x103] = (0xC0000 << 10) | 0xef; + BOOT_PT_SV39[0x104] = (0x100000 << 10) | 0xef; + BOOT_PT_SV39[0x105] = (0x140000 << 10) | 0xef; + } +} + +unsafe fn init_mmu() { + unsafe { + axcpu::asm::write_kernel_page_table(pa!(&raw const BOOT_PT_SV39 as usize)); + axcpu::asm::flush_tlb(None); + } +} + +/// The earliest entry point for the primary CPU. +#[unsafe(naked)] +#[unsafe(no_mangle)] +#[unsafe(link_section = ".text.boot")] +unsafe extern "C" fn _start() -> ! { + // PC = 0x8020_0000 + // a0 = hartid + // a1 = dtb + core::arch::naked_asm!(" + mv s0, a0 // save hartid + mv s1, a1 // save DTB pointer + la sp, {boot_stack} + li t0, {boot_stack_size} + add sp, sp, t0 // setup boot stack + + call {init_boot_page_table} + call {init_mmu} // setup boot page table and enabel MMU + + li s2, {phys_virt_offset} // fix up virtual high address + add sp, sp, s2 + + mv a0, s0 + mv a1, s1 + la a2, {entry} + add a2, a2, s2 + jalr a2 // call_main(cpu_id, dtb) + j .", + phys_virt_offset = const PHYS_VIRT_OFFSET, + boot_stack_size = const BOOT_STACK_SIZE, + boot_stack = sym BOOT_STACK, + init_boot_page_table = sym init_boot_page_table, + init_mmu = sym init_mmu, + entry = sym axplat::call_main, + ) +} + +/// The earliest entry point for secondary CPUs. +#[cfg(feature = "smp")] +#[unsafe(naked)] +pub(crate) unsafe extern fn _start_secondary() -> ! { + // a0 = hartid + // a1 = SP + core::arch::naked_asm!(" + mv s0, a0 // save hartid + mv sp, a1 // set SP + + call {init_mmu} // setup boot page table and enabel MMU + + li s1, {phys_virt_offset} // fix up virtual high address + add a1, a1, s1 + add sp, sp, s1 + + mv a0, s0 + la a1, {entry} + add a1, a1, s1 + jalr a1 // call_secondary_main(cpu_id) + j .", + phys_virt_offset = const PHYS_VIRT_OFFSET, + init_mmu = sym init_mmu, + entry = sym axplat::call_secondary_main, + ) +} diff --git a/platform/riscv64-qemu-virt/src/console.rs b/platform/riscv64-qemu-virt/src/console.rs new file mode 100644 index 00000000..037f5cc6 --- /dev/null +++ b/platform/riscv64-qemu-virt/src/console.rs @@ -0,0 +1,54 @@ +use axplat::console::ConsoleIf; +use kspin::SpinNoIrq; +use lazyinit::LazyInit; +use uart_16550::MmioSerialPort; + +use crate::config::{devices::UART_PADDR, plat::PHYS_VIRT_OFFSET}; + +static UART: LazyInit> = LazyInit::new(); + +pub(crate) fn init_early() { + UART.init_once({ + let mut uart = unsafe { MmioSerialPort::new(UART_PADDR + PHYS_VIRT_OFFSET) }; + uart.init(); + SpinNoIrq::new(uart) + }); +} + +struct ConsoleIfImpl; + +#[impl_plat_interface] +impl ConsoleIf for ConsoleIfImpl { + /// Writes bytes to the console from input u8 slice. + fn write_bytes(bytes: &[u8]) { + for &c in bytes { + let mut uart = UART.lock(); + match c { + b'\n' => { + uart.send_raw(b'\r'); + uart.send_raw(b'\n'); + } + c => uart.send_raw(c), + } + } + } + + /// Reads bytes from the console into the given mutable slice. + /// Returns the number of bytes read. + fn read_bytes(bytes: &mut [u8]) -> usize { + let mut uart = UART.lock(); + for (i, byte) in bytes.iter_mut().enumerate() { + match uart.try_receive() { + Ok(c) => *byte = c, + Err(_) => return i, + } + } + bytes.len() + } + + /// Returns the IRQ number for the console, if applicable. + #[cfg(feature = "irq")] + fn irq_num() -> Option { + Some(crate::config::devices::UART_IRQ) + } +} diff --git a/platform/riscv64-qemu-virt/src/init.rs b/platform/riscv64-qemu-virt/src/init.rs new file mode 100644 index 00000000..f90db4e9 --- /dev/null +++ b/platform/riscv64-qemu-virt/src/init.rs @@ -0,0 +1,40 @@ +use axplat::init::InitIf; + +struct InitIfImpl; + +#[impl_plat_interface] +impl InitIf for InitIfImpl { + /// This function should be called immediately after the kernel has booted, + /// and performed earliest platform configuration and initialization (e.g., + /// early console, clocking). + fn init_early(_cpu_id: usize, _mbi: usize) { + axcpu::init::init_trap(); + crate::console::init_early(); + crate::time::init_early(); + } + + /// Initializes the platform at the early stage for secondary cores. + #[cfg(feature = "smp")] + fn init_early_secondary(_cpu_id: usize) { + axcpu::init::init_trap(); + } + + /// Initializes the platform at the later stage for the primary core. + /// + /// This function should be called after the kernel has done part of its + /// initialization (e.g, logging, memory management), and finalized the rest of + /// platform configuration and initialization. + fn init_later(_cpu_id: usize, _arg: usize) { + #[cfg(feature = "irq")] + crate::irq::init_percpu(); + crate::time::init_percpu(); + } + + /// Initializes the platform at the later stage for secondary cores. + #[cfg(feature = "smp")] + fn init_later_secondary(_cpu_id: usize) { + #[cfg(feature = "irq")] + crate::irq::init_percpu(); + crate::time::init_percpu(); + } +} diff --git a/platform/riscv64-qemu-virt/src/irq.rs b/platform/riscv64-qemu-virt/src/irq.rs new file mode 100644 index 00000000..6e06037d --- /dev/null +++ b/platform/riscv64-qemu-virt/src/irq.rs @@ -0,0 +1,264 @@ +use core::{ + num::NonZeroU32, + ptr::NonNull, + sync::atomic::{AtomicPtr, Ordering}, +}; + +use axplat::{ + irq::{HandlerTable, IpiTarget, IrqHandler, IrqIf}, + percpu::this_cpu_id, +}; +use kspin::SpinNoIrq; +use riscv::register::sie; +use riscv_plic::Plic; +use sbi_rt::HartMask; + +use crate::config::{devices::PLIC_PADDR, plat::PHYS_VIRT_OFFSET}; + +/// Use call_interface with the trait path as known to crate_interface +/// Interface for injecting virtual interrupts to guest VMs. +/// This trait is defined and implemented in the kernel (axvisor). +#[crate_interface::def_interface] +pub trait InjectIrqIf { + fn inject_virtual_interrupt(irq: usize); +} + +/// `Interrupt` bit in `scause` +pub(super) const INTC_IRQ_BASE: usize = 1 << (usize::BITS - 1); + +/// Supervisor software interrupt in `scause` +#[allow(unused)] +pub(super) const S_SOFT: usize = INTC_IRQ_BASE + 1; + +/// Supervisor timer interrupt in `scause` +pub(super) const S_TIMER: usize = INTC_IRQ_BASE + 5; + +/// Supervisor external interrupt in `scause` +pub(super) const S_EXT: usize = INTC_IRQ_BASE + 9; + +static TIMER_HANDLER: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut()); + +static IPI_HANDLER: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut()); + +/// The maximum number of IRQs. +pub const MAX_IRQ_COUNT: usize = 1024; + +static IRQ_HANDLER_TABLE: HandlerTable = HandlerTable::new(); + +static PLIC: SpinNoIrq = SpinNoIrq::new(unsafe { + Plic::new(NonNull::new((PHYS_VIRT_OFFSET + PLIC_PADDR) as *mut _).unwrap()) +}); + +fn this_context() -> usize { + let hart_id = this_cpu_id(); + hart_id * 2 + 1 // supervisor context +} + +pub(super) fn init_percpu() { + // enable soft interrupts, timer interrupts, and external interrupts + unsafe { + sie::set_ssoft(); + sie::set_stimer(); + sie::set_sext(); + } + PLIC.lock().init_by_context(this_context()); +} + +macro_rules! with_cause { + ($cause: expr, @S_TIMER => $timer_op: expr, @S_SOFT => $ipi_op: expr, @S_EXT => $ext_op: expr, @EX_IRQ => $plic_op: expr $(,)?) => { + match $cause { + S_TIMER => $timer_op, + S_SOFT => $ipi_op, + S_EXT => $ext_op, + other => { + if other & INTC_IRQ_BASE == 0 { + // Device-side interrupts read from PLIC + $plic_op + } else { + // Other CPU-side interrupts + panic!("Unknown IRQ cause: {other}"); + } + } + } + }; +} + +struct IrqIfImpl; + +#[impl_plat_interface] +impl IrqIf for IrqIfImpl { + /// Enables or disables the given IRQ. + fn set_enable(irq: usize, enabled: bool) { + with_cause!( + irq, + @S_TIMER => { + unsafe { + if enabled { + sie::set_stimer(); + } else { + sie::clear_stimer(); + } + } + }, + @S_SOFT => {}, + @S_EXT => {}, + @EX_IRQ => { + let Some(irq) = NonZeroU32::new(irq as _) else { + return; + }; + trace!("PLIC set enable: {irq} {enabled}"); + let mut plic = PLIC.lock(); + if enabled { + plic.set_priority(irq, 6); + plic.enable(irq, this_context()); + } else { + plic.disable(irq, this_context()); + } + } + ); + } + + /// Registers an IRQ handler for the given IRQ. + /// + /// It also enables the IRQ if the registration succeeds. It returns `false` if + /// the registration failed. + /// + /// The `irq` parameter has the following semantics + /// 1. If its highest bit is 1, it means it is an interrupt on the CPU side. Its + /// value comes from `scause`, where [`S_SOFT`] represents software interrupt + /// and [`S_TIMER`] represents timer interrupt. If its value is [`S_EXT`], it + /// means it is an external interrupt, and the real IRQ number needs to + /// be obtained from PLIC. + /// 2. If its highest bit is 0, it means it is an interrupt on the device side, + /// and its value is equal to the IRQ number provided by PLIC. + fn register(irq: usize, handler: IrqHandler) -> bool { + with_cause!( + irq, + @S_TIMER => TIMER_HANDLER.compare_exchange(core::ptr::null_mut(), handler as *mut _, Ordering::AcqRel, Ordering::Acquire).is_ok(), + @S_SOFT => IPI_HANDLER.compare_exchange(core::ptr::null_mut(), handler as *mut _, Ordering::AcqRel, Ordering::Acquire).is_ok(), + @S_EXT => { + warn!("External IRQ should be got from PLIC, not scause"); + false + }, + @EX_IRQ => { + if IRQ_HANDLER_TABLE.register_handler(irq, handler) { + Self::set_enable(irq, true); + true + } else { + warn!("register handler for External IRQ {irq} failed"); + false + } + } + ) + } + + /// Unregisters the IRQ handler for the given IRQ. + /// + /// It also disables the IRQ if the unregistration succeeds. It returns the + /// existing handler if it is registered, `None` otherwise. + fn unregister(irq: usize) -> Option { + with_cause!( + irq, + @S_TIMER => { + let handler = TIMER_HANDLER.swap(core::ptr::null_mut(), Ordering::AcqRel); + if !handler.is_null() { + Some(unsafe { core::mem::transmute::<*mut (), IrqHandler>(handler) }) + } else { + None + } + }, + @S_SOFT => { + let handler = IPI_HANDLER.swap(core::ptr::null_mut(), Ordering::AcqRel); + if !handler.is_null() { + Some(unsafe { core::mem::transmute::<*mut (), IrqHandler>(handler) }) + } else { + None + } + }, + @S_EXT => { + warn!("External IRQ should be got from PLIC, not scause"); + None + }, + @EX_IRQ => IRQ_HANDLER_TABLE.unregister_handler(irq).inspect(|_| Self::set_enable(irq, false)) + ) + } + + /// Handles the IRQ. + /// + /// It is called by the common interrupt handler. It should look up in the + /// IRQ handler table and calls the corresponding handler. If necessary, it + /// also acknowledges the interrupt controller after handling. + fn handle(irq: usize) -> Option { + with_cause!( + irq, + @S_TIMER => { + trace!("IRQ: timer"); + let handler = TIMER_HANDLER.load(Ordering::Acquire); + if !handler.is_null() { + // SAFETY: The handler is guaranteed to be a valid function pointer. + unsafe { core::mem::transmute::<*mut (), IrqHandler>(handler)() }; + } + Some(irq) + }, + @S_SOFT => { + trace!("IRQ: IPI"); + let handler = IPI_HANDLER.load(Ordering::Acquire); + if !handler.is_null() { + // SAFETY: The handler is guaranteed to be a valid function pointer. + unsafe { core::mem::transmute::<*mut (), IrqHandler>(handler)() }; + } + Some(irq) + }, + @S_EXT => { + // TODO: judge irq's ownership before handling (axvisor or any vm). + // Maybe later it will be done by registering all irqs IQR_HANDLER_TABLE. + + let mut plic = PLIC.lock(); + let Some(irq) = plic.claim(this_context()) else { + debug!("Spurious external IRQ"); + return None; + }; + drop(plic); + // Inject the virtual interrupt to the guest VM + crate_interface::call_interface!(InjectIrqIf::inject_virtual_interrupt, irq.get() as usize); + + // trace!("IRQ: external {irq}"); + // IRQ_HANDLER_TABLE.handle(irq.get() as usize); + // Only for irqs that belong to axvisor, complete the IRQ. + // plic.complete(this_context(), irq); + Some(irq.get() as usize) + }, + @EX_IRQ => { + unreachable!("Device-side IRQs should be handled by triggering the External Interrupt."); + } + ) + } + + /// Sends an inter-processor interrupt (IPI) to the specified target CPU or all CPUs. + fn send_ipi(_irq_num: usize, target: IpiTarget) { + match target { + IpiTarget::Current { cpu_id } => { + let res = sbi_rt::send_ipi(HartMask::from_mask_base(1 << cpu_id, 0)); + if res.is_err() { + warn!("send_ipi failed: {res:?}"); + } + } + IpiTarget::Other { cpu_id } => { + let res = sbi_rt::send_ipi(HartMask::from_mask_base(1 << cpu_id, 0)); + if res.is_err() { + warn!("send_ipi failed: {res:?}"); + } + } + IpiTarget::AllExceptCurrent { cpu_id, cpu_num } => { + for i in 0..cpu_num { + if i != cpu_id { + let res = sbi_rt::send_ipi(HartMask::from_mask_base(1 << i, 0)); + if res.is_err() { + warn!("send_ipi_all_others failed: {res:?}"); + } + } + } + } + } + } +} diff --git a/platform/riscv64-qemu-virt/src/lib.rs b/platform/riscv64-qemu-virt/src/lib.rs new file mode 100644 index 00000000..32d53817 --- /dev/null +++ b/platform/riscv64-qemu-virt/src/lib.rs @@ -0,0 +1,39 @@ +#![no_std] + +#[macro_use] +extern crate log; +#[macro_use] +extern crate axplat; + +#[cfg(feature = "irq")] +pub mod irq; + +mod boot; +mod console; +mod init; +mod mem; +mod power; +mod time; + +pub mod config { + //! Platform configuration module. + //! + //! If the `AX_CONFIG_PATH` environment variable is set, it will load the configuration from the specified path. + //! Otherwise, it will fall back to the `axconfig.toml` file in the current directory and generate the default configuration. + //! + //! If the `PACKAGE` field in the configuration does not match the package name, it will panic with an error message. + axconfig_macros::include_configs!(path_env = "AX_CONFIG_PATH", fallback = "axconfig.toml"); + assert_str_eq!( + PACKAGE, + env!("CARGO_PKG_NAME"), + "`PACKAGE` field in the configuration does not match the Package name. Please check your configuration file." + ); +} + +pub const fn cpu_count() -> usize { + config::plat::CPU_NUM +} + +pub const fn plic_base() -> usize { + config::devices::PLIC_PADDR +} diff --git a/platform/riscv64-qemu-virt/src/mem.rs b/platform/riscv64-qemu-virt/src/mem.rs new file mode 100644 index 00000000..13000df0 --- /dev/null +++ b/platform/riscv64-qemu-virt/src/mem.rs @@ -0,0 +1,58 @@ +use axplat::mem::{MemIf, PhysAddr, RawRange, VirtAddr, pa, va}; + +use crate::config::devices::MMIO_RANGES; +use crate::config::plat::{ + KERNEL_BASE_PADDR, PHYS_MEMORY_BASE, PHYS_MEMORY_SIZE, PHYS_VIRT_OFFSET, +}; + +struct MemIfImpl; + +#[impl_plat_interface] +impl MemIf for MemIfImpl { + /// Returns all physical memory (RAM) ranges on the platform. + /// + /// All memory ranges except reserved ranges (including the kernel loaded + /// range) are free for allocation. + fn phys_ram_ranges() -> &'static [RawRange] { + // TODO: paser dtb to get the available memory ranges + // We can't directly use `PHYS_MEMORY_BASE` here, because it may has been used by sbi. + &[( + KERNEL_BASE_PADDR, + PHYS_MEMORY_BASE + PHYS_MEMORY_SIZE - KERNEL_BASE_PADDR, + )] + } + + /// Returns all reserved physical memory ranges on the platform. + /// + /// Reserved memory can be contained in [`phys_ram_ranges`], they are not + /// allocatable but should be mapped to kernel's address space. + /// + /// Note that the ranges returned should not include the range where the + /// kernel is loaded. + fn reserved_phys_ram_ranges() -> &'static [RawRange] { + &[] + } + + /// Returns all device memory (MMIO) ranges on the platform. + fn mmio_ranges() -> &'static [RawRange] { + &MMIO_RANGES + } + + /// Translates a physical address to a virtual address. + fn phys_to_virt(paddr: PhysAddr) -> VirtAddr { + va!(paddr.as_usize() + PHYS_VIRT_OFFSET) + } + + /// Translates a virtual address to a physical address. + fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr { + pa!(vaddr.as_usize() - PHYS_VIRT_OFFSET) + } + + /// Returns the kernel address space base virtual address and size. + fn kernel_aspace() -> (VirtAddr, usize) { + ( + va!(crate::config::plat::KERNEL_ASPACE_BASE), + crate::config::plat::KERNEL_ASPACE_SIZE, + ) + } +} diff --git a/platform/riscv64-qemu-virt/src/power.rs b/platform/riscv64-qemu-virt/src/power.rs new file mode 100644 index 00000000..db9e2e0c --- /dev/null +++ b/platform/riscv64-qemu-virt/src/power.rs @@ -0,0 +1,32 @@ +use axplat::power::PowerIf; + +struct PowerImpl; + +#[impl_plat_interface] +impl PowerIf for PowerImpl { + /// Bootstraps the given CPU core with the given initial stack (in physical + /// address). + /// + /// Where `cpu_id` is the logical CPU ID (0, 1, ..., N-1, N is the number of + /// CPU cores on the platform). + #[cfg(feature = "smp")] + fn cpu_boot(cpu_id: usize, stack_top_paddr: usize) { + use axplat::mem::{va, virt_to_phys}; + if sbi_rt::probe_extension(sbi_rt::Hsm).is_unavailable() { + warn!("HSM SBI extension is not supported for current SEE."); + return; + } + let entry = virt_to_phys(va!(crate::boot::_start_secondary as *const () as usize)); + sbi_rt::hart_start(cpu_id, entry.as_usize(), stack_top_paddr); + } + + /// Shutdown the whole system. + fn system_off() -> ! { + info!("Shutting down..."); + sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason); + warn!("It should shutdown!"); + loop { + axcpu::asm::halt(); + } + } +} diff --git a/platform/riscv64-qemu-virt/src/time.rs b/platform/riscv64-qemu-virt/src/time.rs new file mode 100644 index 00000000..5448f73e --- /dev/null +++ b/platform/riscv64-qemu-virt/src/time.rs @@ -0,0 +1,71 @@ +use riscv::register::time; + +use axplat::time::{NANOS_PER_SEC, TimeIf}; + +const NANOS_PER_TICK: u64 = NANOS_PER_SEC / crate::config::devices::TIMER_FREQUENCY as u64; +/// RTC wall time offset in nanoseconds at monotonic time base. +static mut RTC_EPOCHOFFSET_NANOS: u64 = 0; + +pub(super) fn init_early() { + #[cfg(feature = "rtc")] + use crate::config::{devices::RTC_PADDR, plat::PHYS_VIRT_OFFSET}; + + #[cfg(feature = "rtc")] + if RTC_PADDR != 0 { + use riscv_goldfish::Rtc; + + // Get the current time in microseconds since the epoch (1970-01-01) from the riscv RTC. + // Subtract the timer ticks to get the actual time when ArceOS was booted. + let epoch_time_nanos = + Rtc::new(RTC_PADDR + PHYS_VIRT_OFFSET).get_unix_timestamp() * 1_000_000_000; + + unsafe { + RTC_EPOCHOFFSET_NANOS = + epoch_time_nanos - TimeIfImpl::ticks_to_nanos(TimeIfImpl::current_ticks()); + } + } +} + +pub(super) fn init_percpu() { + #[cfg(feature = "irq")] + sbi_rt::set_timer(0); +} + +struct TimeIfImpl; + +#[impl_plat_interface] +impl TimeIf for TimeIfImpl { + /// Returns the current clock time in hardware ticks. + fn current_ticks() -> u64 { + time::read() as u64 + } + + /// Converts hardware ticks to nanoseconds. + fn ticks_to_nanos(ticks: u64) -> u64 { + ticks * NANOS_PER_TICK + } + + /// Converts nanoseconds to hardware ticks. + fn nanos_to_ticks(nanos: u64) -> u64 { + nanos / NANOS_PER_TICK + } + + /// Return epoch offset in nanoseconds (wall time offset to monotonic clock start). + fn epochoffset_nanos() -> u64 { + unsafe { RTC_EPOCHOFFSET_NANOS } + } + + /// Returns the IRQ number for the timer interrupt. + #[cfg(feature = "irq")] + fn irq_num() -> usize { + crate::config::devices::TIMER_IRQ + } + + /// Set a one-shot timer. + /// + /// A timer interrupt will be triggered at the specified monotonic time deadline (in nanoseconds). + #[cfg(feature = "irq")] + fn set_oneshot_timer(deadline_ns: u64) { + sbi_rt::set_timer(Self::nanos_to_ticks(deadline_ns)); + } +} diff --git a/scripts/ostool/qemu-riscv64.toml b/scripts/ostool/qemu-riscv64.toml new file mode 100644 index 00000000..5fcd6412 --- /dev/null +++ b/scripts/ostool/qemu-riscv64.toml @@ -0,0 +1,23 @@ +args = [ + "-nographic", + "-cpu", + "rv64", + "-machine", + "virt", + "-bios", + "default", + "-smp", + "4", + "-device", + "virtio-blk-device,drive=disk0", + "-drive", + "id=disk0,if=none,format=raw,file=${workspaceFolder}/tmp/rootfs.img", + "-append", + "root=/dev/vda rw init=/init", + "-m", + "4g", +] +fail_regex = [] +success_regex = [] +to_bin = true +uefi = false diff --git a/src/hal/arch/aarch64/api.rs b/src/hal/arch/aarch64/api.rs index d6165242..32ca2441 100644 --- a/src/hal/arch/aarch64/api.rs +++ b/src/hal/arch/aarch64/api.rs @@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[axvisor_api::api_mod_impl(axvisor_api::arch)] -mod arch_api_impl { - use core::panic; +use axvisor_api::arch::ArchIf; +use std::os::arceos::modules::axhal::{self, mem::virt_to_phys}; - use axvisor_api::memory::virt_to_phys; +struct ArchImpl; - extern fn hardware_inject_virtual_interrupt(irq: axvisor_api::vmm::InterruptVector) { +#[axvisor_api::api_impl] +impl ArchIf for ArchImpl { + fn hardware_inject_virtual_interrupt(irq: axvisor_api::vmm::InterruptVector) { crate::hal::arch::inject_interrupt(irq as _); } - extern fn read_vgicd_typer() -> u32 { + fn read_vgicd_typer() -> u32 { let mut gic = rdrive::get_one::() .expect("Failed to get GIC driver") .lock() @@ -38,7 +39,7 @@ mod arch_api_impl { panic!("No GIC driver found"); } - extern fn read_vgicd_iidr() -> u32 { + fn read_vgicd_iidr() -> u32 { // use axstd::os::arceos::modules::axhal::irq::MyVgic; // MyVgic::get_gicd().lock().get_iidr() let mut gic = rdrive::get_one::() @@ -57,7 +58,7 @@ mod arch_api_impl { panic!("No GIC driver found"); } - extern fn get_host_gicd_base() -> memory_addr::PhysAddr { + fn get_host_gicd_base() -> memory_addr::PhysAddr { let mut gic = rdrive::get_one::() .expect("Failed to get GIC driver") .lock() @@ -75,7 +76,7 @@ mod arch_api_impl { panic!("No GIC driver found"); } - extern fn get_host_gicr_base() -> memory_addr::PhysAddr { + fn get_host_gicr_base() -> memory_addr::PhysAddr { let mut gic = rdrive::get_one::() .expect("Failed to get GIC driver") .lock() @@ -86,4 +87,23 @@ mod arch_api_impl { } panic!("No GICv3 driver found"); } + + fn fetch_irq() -> u64 { + /// TODO: better implementation + let mut gic = rdrive::get_one::() + .expect("Failed to get GIC driver") + .lock() + .unwrap(); + if let Some(gic) = gic.typed_mut::() { + return u32::from(gic.cpu_interface().ack()) as _; + } + if let Some(gic) = gic.typed_mut::() { + return gic.cpu_interface().ack1().to_u32() as _; + } + panic!("No GIC driver found"); + } + + fn handle_irq() { + axhal::irq::irq_handler(0); + } } diff --git a/src/hal/arch/riscv64/api.rs b/src/hal/arch/riscv64/api.rs new file mode 100644 index 00000000..e45c5704 --- /dev/null +++ b/src/hal/arch/riscv64/api.rs @@ -0,0 +1,8 @@ +struct VmInterruptIfImpl; + +#[crate_interface::impl_interface] +impl axplat_riscv64_qemu_virt::irq::InjectIrqIf for VmInterruptIfImpl { + fn inject_virtual_interrupt(irq: usize) { + crate::hal::arch::inject_interrupt(irq); + } +} diff --git a/src/hal/arch/riscv64/cache.rs b/src/hal/arch/riscv64/cache.rs new file mode 100644 index 00000000..1a905a9d --- /dev/null +++ b/src/hal/arch/riscv64/cache.rs @@ -0,0 +1,5 @@ +use memory_addr::VirtAddr; + +use crate::hal::CacheOp; + +pub fn dcache_range(_op: CacheOp, _addr: VirtAddr, _size: usize) {} diff --git a/src/hal/arch/riscv64/mod.rs b/src/hal/arch/riscv64/mod.rs new file mode 100644 index 00000000..2c14c015 --- /dev/null +++ b/src/hal/arch/riscv64/mod.rs @@ -0,0 +1,31 @@ +mod api; +pub mod cache; + +use crate::vmm::vm_list::get_vm_by_id; +use axaddrspace::{GuestPhysAddr, device::AccessWidth}; +use axvisor_api::vmm::current_vm_id; + +pub fn hardware_check() { + // TODO: implement hardware checks for RISC-V64 + // check page table level like aarch64 +} + +pub fn inject_interrupt(irq_id: usize) { + debug!("injecting interrupt id: {}", irq_id); + + // Get the instance of the vplic, and then inject virtual interrupt. + let vplic = get_vm_by_id(current_vm_id()) + .unwrap() + .get_devices() + .find_mmio_dev(GuestPhysAddr::from_usize(axruntime::plic_base())) + .unwrap(); + + // Calulate the pending register offset and value. + let reg_offset = riscv_vplic::PLIC_PENDING_OFFSET + (irq_id / 32) * 4; + let addr = GuestPhysAddr::from_usize(axruntime::plic_base() + reg_offset); + let width = AccessWidth::Dword; + let val: u32 = 1 << (irq_id % 32); + + // Use a trick write to set the pending bit. + let _ = vplic.handle_write(addr, width, val as _); +} diff --git a/src/hal/impl_host.rs b/src/hal/impl_host.rs new file mode 100644 index 00000000..831160f9 --- /dev/null +++ b/src/hal/impl_host.rs @@ -0,0 +1,10 @@ +use axvisor_api::host::HostIf; + +struct HostImpl; + +#[axvisor_api::api_impl] +impl HostIf for HostImpl { + fn get_host_cpu_num() -> usize { + std::os::arceos::modules::axhal::cpu_num() + } +} diff --git a/src/hal/impl_memory.rs b/src/hal/impl_memory.rs new file mode 100644 index 00000000..1479255f --- /dev/null +++ b/src/hal/impl_memory.rs @@ -0,0 +1,53 @@ +use core::{alloc::Layout, ptr::NonNull}; + +use std::os::arceos; + +use axaddrspace::{AxMmHal, HostPhysAddr, HostVirtAddr}; +use axvisor_api::memory::MemoryIf; +use memory_addr::PAGE_SIZE_4K; + +use crate::hal::AxMmHalImpl; + +struct MemoryImpl; + +#[axvisor_api::api_impl] +impl MemoryIf for MemoryImpl { + fn alloc_frame() -> Option { + ::alloc_frame() + } + + fn alloc_contiguous_frames(num_frames: usize, frame_align_pow2: usize) -> Option { + arceos::modules::axalloc::global_allocator() + .alloc( + Layout::from_size_align( + num_frames * PAGE_SIZE_4K, + PAGE_SIZE_4K << frame_align_pow2, + ) + .unwrap(), + ) + // .alloc_pages(num_frames, PAGE_SIZE_4K << frame_align_pow2) + // .map(|vaddr| ::virt_to_phys(vaddr.into())) + .map(|vaddr| HostPhysAddr::from(vaddr.as_ptr() as usize)) + .ok() + } + + fn dealloc_frame(paddr: HostPhysAddr) { + ::dealloc_frame(paddr) + } + + fn dealloc_contiguous_frames(paddr: HostPhysAddr, num_frames: usize) { + // arceos::modules::axalloc::global_allocator().dealloc_pages(paddr.as_usize(), num_frames); + arceos::modules::axalloc::global_allocator().dealloc( + unsafe { NonNull::new_unchecked(paddr.as_usize() as _) }, + Layout::from_size_align(num_frames * PAGE_SIZE_4K, PAGE_SIZE_4K).unwrap(), + ); + } + + fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr { + ::phys_to_virt(paddr) + } + + fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr { + ::virt_to_phys(vaddr) + } +} diff --git a/src/hal/impl_time.rs b/src/hal/impl_time.rs new file mode 100644 index 00000000..2c275899 --- /dev/null +++ b/src/hal/impl_time.rs @@ -0,0 +1,33 @@ +use std::os::arceos::modules::axhal; + +use axvisor_api::time::{CancelToken, Nanos, Ticks, TimeIf, TimeValue}; + +use crate::vmm; + +struct TimeImpl; + +#[axvisor_api::api_impl] +impl TimeIf for TimeImpl { + fn current_ticks() -> Ticks { + axhal::time::current_ticks() + } + + fn ticks_to_nanos(ticks: Ticks) -> Nanos { + axhal::time::ticks_to_nanos(ticks) + } + + fn nanos_to_ticks(nanos: Nanos) -> Ticks { + axhal::time::nanos_to_ticks(nanos) + } + + fn register_timer( + deadline: TimeValue, + handler: alloc::boxed::Box, + ) -> CancelToken { + vmm::timer::register_timer(deadline.as_nanos() as u64, handler) + } + + fn cancel_timer(token: CancelToken) { + vmm::timer::cancel_timer(token) + } +} diff --git a/src/hal/impl_vmm.rs b/src/hal/impl_vmm.rs new file mode 100644 index 00000000..44717cc4 --- /dev/null +++ b/src/hal/impl_vmm.rs @@ -0,0 +1,74 @@ +use std::os::arceos::modules::{axhal, axtask}; + +use axaddrspace::{HostPhysAddr, HostVirtAddr}; +use axerrno::{AxResult, ax_err_type}; +use axvisor_api::vmm::{InterruptVector, VCpuId, VCpuSet, VMId, VmmIf}; + +use crate::{task::AsVCpuTask, vmm}; + +struct VmmImpl; + +fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr { + axhal::mem::virt_to_phys(vaddr) +} + +fn current_time_nanos() -> u64 { + axhal::time::monotonic_time_nanos() +} + +fn current_vm_id() -> usize { + axtask::current().as_vcpu_task().vm().id() +} + +fn current_vcpu_id() -> usize { + axtask::current().as_vcpu_task().vcpu.id() +} + +fn current_pcpu_id() -> usize { + axhal::percpu::this_cpu_id() +} + +fn vcpu_resides_on(vm_id: usize, vcpu_id: usize) -> AxResult { + vmm::with_vcpu_task(vm_id, vcpu_id, |task| task.cpu_id() as usize) + .ok_or_else(|| ax_err_type!(NotFound)) +} + +fn inject_irq_to_vcpu(vm_id: usize, vcpu_id: usize, irq: usize) -> AxResult { + vmm::with_vm_and_vcpu_on_pcpu(vm_id, vcpu_id, move |_, vcpu| { + vcpu.inject_interrupt(irq).unwrap(); + }) +} + +#[axvisor_api::api_impl] +impl VmmIf for VmmImpl { + fn current_vm_id() -> usize { + axtask::current().as_vcpu_task().vm().id() + } + + fn current_vcpu_id() -> usize { + axtask::current().as_vcpu_task().vcpu.id() + } + + fn vcpu_num(vm_id: VMId) -> Option { + vmm::with_vm(vm_id, |vm| vm.vcpu_num()) + } + + fn active_vcpus(_vm_id: VMId) -> Option { + todo!("active_vcpus") + } + + fn inject_interrupt(vm_id: VMId, vcpu_id: VCpuId, vector: InterruptVector) { + let _ = vmm::with_vm_and_vcpu_on_pcpu(vm_id, vcpu_id, move |_, vcpu| { + vcpu.inject_interrupt(vector as usize).unwrap(); + }); + } + + fn inject_interrupt_to_cpus(_vm_id: VMId, _vcpu_set: VCpuSet, _vector: InterruptVector) { + todo!("inject_interrupt_to_cpus") + } + + fn notify_vcpu_timer_expired(_vm_id: VMId, _vcpu_id: VCpuId) { + todo!("notify_vcpu_timer_expired") + // vmm::timer::notify_timer_expired(vm_id, vcpu_id); + } +} diff --git a/src/hal/mod.rs b/src/hal/mod.rs index afc0070b..183c7c79 100644 --- a/src/hal/mod.rs +++ b/src/hal/mod.rs @@ -12,25 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::os::arceos::{ - self, - modules::{axhal::percpu::this_cpu_id, axtask}, -}; - -use axerrno::{AxResult, ax_err_type}; -use memory_addr::PAGE_SIZE_4K; -use page_table_multiarch::PagingHandler; +use std::os::arceos::{self, modules::axhal::percpu::this_cpu_id}; use arceos::modules::axhal; use axaddrspace::{AxMmHal, HostPhysAddr, HostVirtAddr}; -use axvcpu::AxVCpuHal; -use axvm::{AxVMHal, AxVMPerCpu}; +use axvm::AxVMPerCpu; +use page_table_multiarch::PagingHandler; #[cfg_attr(target_arch = "aarch64", path = "arch/aarch64/mod.rs")] #[cfg_attr(target_arch = "x86_64", path = "arch/x86_64/mod.rs")] +#[cfg_attr(target_arch = "riscv64", path = "arch/riscv64/mod.rs")] pub mod arch; -use crate::{hal::arch::hardware_check, task::AsVCpuTask, vmm}; +use crate::{hal::arch::hardware_check, vmm}; #[allow(unused)] #[repr(C)] @@ -44,58 +38,20 @@ pub enum CacheOp { CleanAndInvalidate, } -/// Implementation for `AxVMHal` trait. -pub struct AxVMHalImpl; - -impl AxVMHal for AxVMHalImpl { - type PagingHandler = axhal::paging::PagingHandlerImpl; - - fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr { - axhal::mem::virt_to_phys(vaddr) - } - - fn current_time_nanos() -> u64 { - axhal::time::monotonic_time_nanos() - } - - fn current_vm_id() -> usize { - axtask::current().as_vcpu_task().vm().id() - } - - fn current_vcpu_id() -> usize { - axtask::current().as_vcpu_task().vcpu.id() - } - - fn current_pcpu_id() -> usize { - axhal::percpu::this_cpu_id() - } - - fn vcpu_resides_on(vm_id: usize, vcpu_id: usize) -> AxResult { - vmm::with_vcpu_task(vm_id, vcpu_id, |task| task.cpu_id() as usize) - .ok_or_else(|| ax_err_type!(NotFound)) - } - - fn inject_irq_to_vcpu(vm_id: usize, vcpu_id: usize, irq: usize) -> AxResult { - vmm::with_vm_and_vcpu_on_pcpu(vm_id, vcpu_id, move |_, vcpu| { - vcpu.inject_interrupt(irq).unwrap(); - }) - } -} - pub struct AxMmHalImpl; impl AxMmHal for AxMmHalImpl { fn alloc_frame() -> Option { - ::PagingHandler::alloc_frame() + ::alloc_frame() } fn dealloc_frame(paddr: HostPhysAddr) { - ::PagingHandler::dealloc_frame(paddr) + ::dealloc_frame(paddr) } #[inline] fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr { - ::PagingHandler::phys_to_virt(paddr) + ::phys_to_virt(paddr) } fn virt_to_phys(vaddr: axaddrspace::HostVirtAddr) -> axaddrspace::HostPhysAddr { @@ -103,18 +59,18 @@ impl AxMmHal for AxMmHalImpl { } } -pub struct AxVCpuHalImpl; +// pub struct AxVCpuHalImpl; -impl AxVCpuHal for AxVCpuHalImpl { - type MmHal = AxMmHalImpl; +// impl AxVCpuHal for AxVCpuHalImpl { +// type MmHal = AxMmHalImpl; - fn irq_hanlder() { - axhal::irq::irq_handler(0); - } -} +// fn irq_hanlder() { +// axhal::irq::irq_handler(0); +// } +// } #[percpu::def_percpu] -static mut AXVM_PER_CPU: AxVMPerCpu = AxVMPerCpu::::new_uninit(); +static mut AXVM_PER_CPU: AxVMPerCpu = AxVMPerCpu::new_uninit(); /// Init hardware virtualization support in each core. pub(crate) fn enable_virtualization() { @@ -173,119 +129,7 @@ pub(crate) fn enable_virtualization() { info!("All cores have enabled hardware virtualization support."); } -#[axvisor_api::api_mod_impl(axvisor_api::memory)] -mod memory_api_impl { - use core::{alloc::Layout, ptr::NonNull}; - - use super::*; - - extern fn alloc_frame() -> Option { - ::alloc_frame() - } - - extern fn alloc_contiguous_frames( - num_frames: usize, - frame_align_pow2: usize, - ) -> Option { - arceos::modules::axalloc::global_allocator() - .alloc( - Layout::from_size_align( - num_frames * PAGE_SIZE_4K, - PAGE_SIZE_4K << frame_align_pow2, - ) - .unwrap(), - ) - // .alloc_pages(num_frames, PAGE_SIZE_4K << frame_align_pow2) - // .map(|vaddr| ::virt_to_phys(vaddr.into())) - .map(|vaddr| HostPhysAddr::from(vaddr.as_ptr() as usize)) - .ok() - } - - extern fn dealloc_frame(paddr: HostPhysAddr) { - ::dealloc_frame(paddr) - } - - extern fn dealloc_contiguous_frames(paddr: HostPhysAddr, num_frames: usize) { - // arceos::modules::axalloc::global_allocator().dealloc_pages(paddr.as_usize(), num_frames); - arceos::modules::axalloc::global_allocator().dealloc( - unsafe { NonNull::new_unchecked(paddr.as_usize() as _) }, - Layout::from_size_align(num_frames * PAGE_SIZE_4K, PAGE_SIZE_4K).unwrap(), - ); - } - - extern fn phys_to_virt(paddr: HostPhysAddr) -> HostVirtAddr { - ::phys_to_virt(paddr) - } - - extern fn virt_to_phys(vaddr: HostVirtAddr) -> HostPhysAddr { - ::virt_to_phys(vaddr) - } -} - -#[axvisor_api::api_mod_impl(axvisor_api::time)] -mod time_api_impl { - use super::*; - use axvisor_api::time::{CancelToken, Nanos, Ticks, TimeValue}; - - extern fn current_ticks() -> Ticks { - axhal::time::current_ticks() - } - - extern fn ticks_to_nanos(ticks: Ticks) -> Nanos { - axhal::time::ticks_to_nanos(ticks) - } - - extern fn nanos_to_ticks(nanos: Nanos) -> Ticks { - axhal::time::nanos_to_ticks(nanos) - } - - extern fn register_timer( - deadline: TimeValue, - handler: alloc::boxed::Box, - ) -> CancelToken { - vmm::timer::register_timer(deadline.as_nanos() as u64, handler) - } - - extern fn cancel_timer(token: CancelToken) { - vmm::timer::cancel_timer(token) - } -} - -#[axvisor_api::api_mod_impl(axvisor_api::vmm)] -mod vmm_api_impl { - use super::*; - use axvisor_api::vmm::{InterruptVector, VCpuId, VMId}; - - extern fn current_vm_id() -> usize { - ::current_vm_id() - } - - extern fn current_vcpu_id() -> usize { - ::current_vcpu_id() - } - - extern fn vcpu_num(vm_id: VMId) -> Option { - vmm::with_vm(vm_id, |vm| vm.vcpu_num()) - } - - extern fn active_vcpus(_vm_id: VMId) -> Option { - todo!("active_vcpus") - } - - extern fn inject_interrupt(vm_id: VMId, vcpu_id: VCpuId, vector: InterruptVector) { - ::inject_irq_to_vcpu(vm_id, vcpu_id, vector as usize).unwrap(); - } - - extern fn notify_vcpu_timer_expired(_vm_id: VMId, _vcpu_id: VCpuId) { - todo!("notify_vcpu_timer_expired") - // vmm::timer::notify_timer_expired(vm_id, vcpu_id); - } -} - -#[axvisor_api::api_mod_impl(axvisor_api::host)] -mod host_api_impl { - extern fn get_host_cpu_num() -> usize { - // std::os::arceos::modules::axconfig::plat::CPU_NUM - std::os::arceos::modules::axhal::cpu_num() - } -} +mod impl_host; +mod impl_memory; +mod impl_time; +mod impl_vmm; diff --git a/src/main.rs b/src/main.rs index 99721034..f9093226 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ #![no_std] #![no_main] #![feature(used_with_arg)] +#![cfg(target_os = "none")] #[macro_use] extern crate log; diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 1ae83994..82610474 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -125,7 +125,13 @@ impl ImageLoader { self.vm.clone(), ); } else { - info!("dtb_load_gpa not provided"); + if let Some(buffer) = vm_imags.dtb { + #[cfg(target_arch = "riscv64")] + load_vm_image_from_memory(buffer, self.dtb_load_gpa.unwrap(), self.vm.clone()) + .expect("Failed to load DTB images"); + } else { + info!("dtb_load_gpa not provided"); + } } // Load BIOS image diff --git a/src/vmm/mod.rs b/src/vmm/mod.rs index cbbfb8d4..e9e64737 100644 --- a/src/vmm/mod.rs +++ b/src/vmm/mod.rs @@ -32,18 +32,15 @@ use std::os::arceos::{ use axerrno::{AxResult, ax_err_type}; -use crate::{ - hal::{AxVCpuHalImpl, AxVMHalImpl}, - task::AsVCpuTask, -}; +use crate::task::AsVCpuTask; pub use timer::init_percpu as init_timer_percpu; /// The instantiated VM type. -pub type VM = axvm::AxVM; +pub type VM = axvm::AxVM; /// The instantiated VM ref type (by `Arc`). -pub type VMRef = axvm::AxVMRef; +pub type VMRef = axvm::AxVMRef; /// The instantiated VCpu ref type (by `Arc`). -pub type VCpuRef = axvm::AxVCpuRef; +pub type VCpuRef = axvm::AxVCpuRef; static VMM: AxWaitQueueHandle = AxWaitQueueHandle::new(); diff --git a/src/vmm/vcpus.rs b/src/vmm/vcpus.rs index b80bcc79..5a26355d 100644 --- a/src/vmm/vcpus.rs +++ b/src/vmm/vcpus.rs @@ -323,16 +323,17 @@ fn vcpu_on(vm: VMRef, vcpu_id: usize, entry_point: GuestPhysAddr, arg: usize) { vcpu.set_entry(entry_point) .expect("vcpu_on: set_entry failed"); + #[cfg(not(target_arch = "riscv64"))] vcpu.set_gpr(0, arg); #[cfg(target_arch = "riscv64")] { - debug!( + info!( "vcpu_on: vcpu[{}] entry={:x} opaque={:x}", vcpu_id, entry_point, arg ); - vcpu.set_gpr(0, vcpu_id); - vcpu.set_gpr(1, arg); + vcpu.set_gpr(riscv_vcpu::GprIndex::A0 as usize, vcpu_id); + vcpu.set_gpr(riscv_vcpu::GprIndex::A1 as usize, arg); } let vcpu_task = alloc_vcpu_task(&vm, vcpu); @@ -521,7 +522,10 @@ fn vcpu_run() { }); vcpu_on(vm.clone(), target_vcpu_id, entry_point, arg as _); + #[cfg(not(target_arch = "riscv64"))] vcpu.set_gpr(0, 0); + #[cfg(target_arch = "riscv64")] + vcpu.set_gpr(riscv_vcpu::GprIndex::A0 as usize, 0); } AxVCpuExitReason::SystemDown => { warn!("VM[{vm_id}] run VCpu[{vcpu_id}] SystemDown"); diff --git a/xtask/src/cargo.rs b/xtask/src/cargo.rs index f5262e49..55f8322a 100644 --- a/xtask/src/cargo.rs +++ b/xtask/src/cargo.rs @@ -25,6 +25,8 @@ impl Context { Arch::Aarch64 } else if build_config.target.contains("x86_64") { Arch::X86_64 + } else if build_config.target.contains("riscv64") { + Arch::Riscv64 } else { return Err(anyhow::anyhow!( "Unsupported target architecture: {}", @@ -37,15 +39,14 @@ impl Context { } else { PathBuf::from(format!(".qemu-{arch:?}.toml").to_lowercase()) }; + let default_config_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("scripts") + .join("ostool") + .join(format!("qemu-{arch:?}.toml").to_lowercase()); // If the configuration file does not exist, copy from the default location if !config_path.exists() { - fs::copy( - PathBuf::from("scripts") - .join("ostool") - .join(format!("qemu-{arch:?}.toml").to_lowercase()), - &config_path, - )?; + fs::copy(&default_config_path, &config_path)?; } let kind = CargoRunnerKind::Qemu { @@ -78,4 +79,5 @@ impl Context { enum Arch { Aarch64, X86_64, + Riscv64, } diff --git a/xtask/src/tbuld.rs b/xtask/src/tbuld.rs index 6b7f85b2..addc62e8 100644 --- a/xtask/src/tbuld.rs +++ b/xtask/src/tbuld.rs @@ -46,11 +46,10 @@ impl Context { config_path = c.clone(); } - std::fs::write( - config_path.parent().unwrap().join(".build-schema.json"), - serde_json::to_string_pretty(&json).unwrap(), - ) - .with_context(|| "Failed to write schema file .build-schema.json")?; + let path = config_path.parent().unwrap().join(".build-schema.json"); + + std::fs::write(&path, serde_json::to_string_pretty(&json).unwrap()) + .with_context(|| format!("Failed to write schema file: {}", path.display()))?; let config_str = std::fs::read_to_string(&config_path) .with_context(|| format!("Failed to read config file: {}", config_path.display()))?; @@ -91,6 +90,18 @@ impl Context { to_bin: config.to_bin, ..Default::default() }; + if cargo.target == "aarch64-unknown-none-softfloat" + && cargo.features.iter().any(|feature| feature == "dyn-plat") + { + // Dynamic-platform AArch64 builds link as PIE, so core/alloc must be + // rebuilt with the same PIC settings instead of using prebuilt std. + ensure_cargo_arg_pair(&mut cargo.args, "-Z", "build-std=core,alloc"); + ensure_cargo_arg_pair( + &mut cargo.args, + "-Z", + "build-std-features=compiler-builtins-mem", + ); + } cargo.args.extend(config.cargo_args); if let Some(smp) = config.smp { @@ -119,3 +130,14 @@ impl Context { Ok(()) } } + +fn ensure_cargo_arg_pair(args: &mut Vec, flag: &str, value: &str) { + if args + .windows(2) + .any(|window| window[0] == flag && window[1] == value) + { + return; + } + args.push(flag.to_string()); + args.push(value.to_string()); +}