diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index e875baef..00000000 --- a/.cargo/config +++ /dev/null @@ -1,15 +0,0 @@ -# 编译的目标平台 -[build] -# target = "riscv64gc-unknown-none-elf" -target = "riscv64imac-unknown-none-elf" - -# 使用我们的 linker script 来进行链接 -[target.riscv64gc-unknown-none-elf] -rustflags = [ - "-Clink-arg=-T.cargo/linker-riscv.ld", -] - -[target.riscv64imac-unknown-none-elf] -rustflags = [ - "-Clink-arg=-T.cargo/linker-riscv.ld", -] \ No newline at end of file diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..b026b6e8 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,33 @@ +# 编译的目标平台 +[build] +target = 'riscv64gc-unknown-none-elf' +# target = 'x86_64-unknown-none' +# target = 'aarch64-unknown-none-softfloat' +# target = 'loongarch64-unknown-none' + +# This flags also can be set from every target. +rustflags = [ + '-Cforce-frame-pointers=yes', + '-Clink-arg=-no-pie', + '--cfg=board="qemu"', + '--cfg=root_fs="fat32"', + '-Zunstable-options', + '-Ztls-model=local-exec', + # '--cfg=driver="kvirtio,kgoldfish-rtc,ns16550a"', + # '--extern=force:kernel' + # '-Zunstable-options', + # '--check-cfg=values(board, "qemu","k210","cv1811h", "knvme", "")', + # '--cfg=kernel_base="0xffffffc080200000"', # riscv64imac-unknown-none-elf + # '--cfg=kernel_base="0xffffff8000200000"', # x86_64-unknown-none +] + +[env] +ROOT_MANIFEST_DIR = "../" + +[target.riscv64imac-unknown-none-elf] +[target.x86_64-unknown-none] +[target.aarch64-unknown-none-softfloat] +[target.loongarch64-unknown-none] + +[unstable] +features = ['dev_dep','host_dep'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..42722121 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: CI + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + make-run: + runs-on: ubuntu-latest + # strategy: + # fail-fast: false + # matrix: + # arch: [riscv64, aarch64, x86_64, loongarch64] + steps: + - name: Install qemu-system + run: sudo apt update && sudo apt install qemu-system -y + - name: Install cargo-binutils + run: cargo install cargo-binutils + - name: Install kbuild + run: cargo install kbuild + + - uses: actions/checkout@v4 + - name: Install toolchain + run: rustup show && cargo -Vv && rustc -Vv + - run: rustup default nightly && cargo -Vv && rustc -Vv + + - name: "[riscv64] make run" + run: make BIN=riscv64-qemu run + - name: "[aarch64] make run" + run: make BIN=aarch64-qemu run + # It takes 20 minutes to succeed. + # - name: "[x86_64] make run" + # run: make BIN=x86_64-qemu run + # FIXME: qemu-system-loongarch64: command not found + - name: "[loongarch64] make run" + run: make BIN=loongarch64-qemu run + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # FIXME: Could not find incbin file '../mount.img' + # - name: build + # run: cargo build + + - uses: taiki-e/install-action@cargo-hack + - run: cargo hack clippy --each-feature diff --git a/.gitignore b/.gitignore index 9f970225..e6515c8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,14 @@ -target/ \ No newline at end of file +target/ +mount.img +mount/ +sbi-qemu +kernel-qemu +byteos.bin +.cargo/linker-riscv.ld +packets.pcap +.gdb_history +kernel/*.lds +qemu.log +kernel/src/drivers.rs +graph.png +tools/iso/example diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..8230c019 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdb", + "request": "attach", + "name": "Attach to Qemu", + "executable": "${userHome}/Code/ByteOS/target/riscv64imac-unknown-none-elf/debug/kernel", + "target": ":1234",//不能和Qemu开放的tcp端口重叠 + "remote": true, + "cwd": "${workspaceRoot}", + "valuesFormatting": "parseText", + "gdbpath": "gdb-multiarch", + "preLaunchTask": "Build", + "showDevDebugOutput":true, + "internalConsoleOptions": "openOnSessionStart", + "printCalls": true, + "stopAtConnect": true, + "qemuPath": "qemu-system-riscv64", + "qemuArgs": [ + "-machine", + "virt", + "-kernel", + "target/riscv64imac-unknown-none-elf/debug/kernel", + "-m", + "128M", + "-bios", + "tools/opensbi-qemu.bin", + "-nographic", + "-smp", + "1", + "-drive", + "file=mount.img,if=none,format=raw,id=x0", + "-device", + "virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0", + "-s", + "-S" + ], + "userSpaceDebuggeeFolder":"/home/yufeng/Code/Starry/testcases/sdcard", + "KERNEL_IN_BREAKPOINTS_LINE":14, // src/trap/mod.rs中内核入口行号。可能要修改 + "KERNEL_OUT_BREAKPOINTS_LINE":750, // src/trap/mod.rs中内核出口行号。可能要修改 + "GO_TO_KERNEL_LINE":30, // src/trap/mod.rs中,用于从用户态返回内核的断点行号。在rCore-Tutorial-v3中,这是set_user_trap_entry函数中的stvec::write(TRAMPOLINE as usize, TrapMode::Direct);语句。 + "KERNEL_IN_BREAKPOINTS_FILENAME":"/home/yufeng/Code/Starry/modules/axhal/src/arch/x86_64/trap.rs", + "KERNEL_OUT_BREAKPOINTS_FILENAME":"/home/yufeng/Code/Starry/modules/axtask/src/task.rs", + "GO_TO_KERNEL_FILENAME":"src/trap/mod.rs" + }, + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d4f3f84..3084effd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,6 @@ { - "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.checkOnSave.extraArgs": [ - "--target", - "riscv64gc-unknown-none-elf" - ] + "rust-analyzer.check.allTargets": false, + "rust-analyzer.check.extraArgs": [], + "rust-analyzer.procMacro.enable": true, + "deno.enable": true } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..3b58d7dc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,22 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", // 任务的名字叫Build,注意是大小写区分的,等会在launch中调用这个名字 + "type": "shell", // 任务执行的是shell命令,也可以是 + "command": "make", + "args": [ + "LOG=debug", + // "RELEASE=debug", + "justbuild" + ], + "group": { + "kind": "build", + "isDefault": true + // 任务分组,因为是tasks而不是task,意味着可以连着执行很多任务 + // 在build组的任务们,可以通过在Command Palette(F1) 输入run build task来运行 + // 当然,如果任务分组是test,你就可以用run test task来运行 + }, + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 5f7fcc03..6413a6c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,12 +3,114 @@ version = 3 [[package]] -name = "arch" +name = "aarch64-cpu" +version = "9.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac42a04a61c19fc8196dd728022a784baecc5d63d7e256c01ad1b3fbfab26287" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "allocator" version = "0.1.0" +source = "git+https://github.com/Byte-OS/allocator.git?rev=c6ce949146d5feab1d406502b19b035f5d392c35#c6ce949146d5feab1d406502b19b035f5d392c35" dependencies = [ + "buddy_system_allocator", "log", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "arm_gicv2" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d25e73c949c69f75d1b9dba39c5475523403b31eb8c2fdc99da4dc33bc1aca" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "arm_pl011" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efcf6afca4502993a737ba1e00952d1321078689da92bf7aab27d4e5756c0bec" +dependencies = [ + "tock-registers", +] + +[[package]] +name = "async-recursion" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c5ef0ede93efbf733c1a727f3b6b5a1060bbedd5600183e66f6e4be4af0ec5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b645c5c09a7d4035949cfce1a915785aaad6f17800c35fda8a8c311c491f284" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "buddy_system_allocator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f9365b6b0c9e1663ca4ca9440c00eda46bc85a3407070be8b5e0d8d1f29629" +dependencies = [ + "spin", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "cfg-if" version = "1.0.0" @@ -16,15 +118,291 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "console" +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "cstr_core" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" +dependencies = [ + "cty", + "memchr", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "devfs" version = "0.1.0" +source = "git+https://github.com/Byte-OS/devfs.git#c5e510dfbedbe42866fa4ab23fecfd8d7f596dff" +dependencies = [ + "bitflags 2.4.2", + "devices", + "hal", + "log", + "logging", + "num-derive", + "num-traits", + "sync", + "vfscore", +] + +[[package]] +name = "devices" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/devices.git#89a7844a041117af8465b2f484f3627aef929a32" +dependencies = [ + "fdt", + "frame_allocator", + "linkme", + "log", + "polyhal", + "sync", + "timestamp", + "virtio-drivers", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "executor" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/executor.git#7cab69999a3b48e12addd861dfaa4471fd8afba9" +dependencies = [ + "downcast-rs", + "hashbrown", + "log", + "polyhal", + "sync", +] + +[[package]] +name = "ext4_rs" +version = "1.0.0" +source = "git+https://github.com/yuoo655/ext4_rs.git?rev=04286c7#04286c79da45154a7e007a7ef73bcbe5cad073e1" +dependencies = [ + "bitflags 2.4.2", + "log", +] + +[[package]] +name = "fatfs" +version = "0.4.0" +source = "git+https://github.com/byte-os/rust-fatfs.git#3b45ddc5f3991f1a59040404e14da19d149f1dbf" +dependencies = [ + "bitflags 1.3.2", + "log", +] + +[[package]] +name = "fdt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" + +[[package]] +name = "frame_allocator" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/bit_frame_allocator.git#b989b6a4e17d960fca1e77c83f060cb6006fc924" +dependencies = [ + "bit_field", + "log", + "polyhal", + "sync", +] + +[[package]] +name = "fs" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/fs.git#79f9b3e25c9d7eb72bfbb62c1d3f6ba6ce3cfbb0" +dependencies = [ + "devfs", + "devices", + "ext4_rs", + "fatfs", + "frame_allocator", + "log", + "logging", + "lwext4_rust", + "procfs", + "ramfs", + "sync", + "vfscore", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "general-plic" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/driver-general-plic.git#d6196a18a523e297123aa5bca7249f112a732486" +dependencies = [ + "devices", + "log", +] + +[[package]] +name = "hal" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/hal.git#6f40272c10b59062dfb3dc37de2fddf58912002e" +dependencies = [ + "frame_allocator", + "log", + "polyhal", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] [[package]] name = "kernel" version = "0.1.0" dependencies = [ + "allocator", + "async-recursion", + "bit_field", + "bitflags 2.4.2", + "cfg-if", + "devices", + "executor", + "fdt", + "frame_allocator", + "fs", + "futures-lite", + "general-plic", + "hal", + "hashbrown", + "kgoldfish-rtc", + "kramdisk", + "kvirtio", + "log", "logging", - "panic_handler", + "lose-net-stack", + "ns16550a 0.1.0", + "num-derive", + "num-traits", + "polyhal", + "serde", + "serde_derive", + "signal", + "sync", + "toml", + "vfscore", + "xmas-elf", +] + +[[package]] +name = "kgoldfish-rtc" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/driver-kgoldfish-rtc.git#66e0234f67f68072a634cf2c02afa341c8e8f7a2" +dependencies = [ + "devices", + "log", + "timestamp", +] + +[[package]] +name = "kramdisk" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/kramdisk.git#9eb2394b52c5af15dcbadbf9bd1af2979df3c20c" +dependencies = [ + "devices", + "log", + "virtio-drivers", +] + +[[package]] +name = "kvirtio" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/driver-kvirtio.git#5917abe91c1d6ba998c893abd33404c6c3eb140d" +dependencies = [ + "devices", + "log", + "virtio-drivers", +] + +[[package]] +name = "linkme" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b53ad6a33de58864705954edb5ad5d571a010f9e296865ed43dc72a5621b430" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e542a18c94a9b6fcc7adb090fa3ba6b79ee220a16404f325672729f32a66ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", ] [[package]] @@ -39,15 +417,468 @@ dependencies = [ [[package]] name = "logging" version = "0.1.0" +source = "git+https://github.com/Byte-OS/logging.git#242f79a5628f9d2dfa79b287bca6125575ce98bf" dependencies = [ - "arch", + "devices", "log", + "polyhal", + "sync", ] [[package]] -name = "panic_handler" +name = "loongArch64" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd48200d465466664e4e899b204b77b5447d60b1ababdad3a2c49ae85417b552" +dependencies = [ + "bit_field", + "bitflags 1.3.2", +] + +[[package]] +name = "lose-net-stack" version = "0.1.0" +source = "git+https://github.com/byte-os/lose-net-stack?rev=bb99460#bb99460fc226b13e3fd1c7689139c325e9d713ce" dependencies = [ - "arch", - "logging", + "bitflags 2.4.2", + "log", + "num_enum", + "spin", +] + +[[package]] +name = "lwext4_rust" +version = "0.2.0" +source = "git+https://github.com/elliott10/lwext4_rust.git#238d3a2560353679f0c577686006d41ed48a0f56" +dependencies = [ + "log", + "printf-compat", +] + +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "multiboot" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87ad3b7b7bcf5da525c22221e3eb3a020cd68b2d55ae62f629c15e8bc3bd56e" +dependencies = [ + "paste", +] + +[[package]] +name = "ns16550a" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/driver-ns16550a.git#059e0f27aa0b37a7d3a4dfda16679eafb33a5da4" +dependencies = [ + "devices", + "log", + "ns16550a 0.2.0", +] + +[[package]] +name = "ns16550a" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38464b781e571e0447c11c029ce798383b5e79ac3270df63b3254192a05458d" + +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "polyhal" +version = "0.1.3" +source = "git+https://github.com/Byte-OS/polyhal.git#5b890102fb32de0ca0f7c3e7a776454b6d0bd583" +dependencies = [ + "aarch64-cpu", + "arm_gicv2", + "arm_pl011", + "bitflags 2.4.2", + "cfg-if", + "fdt", + "log", + "loongArch64", + "multiboot", + "polyhal-macro", + "raw-cpuid 11.0.1", + "riscv", + "sbi-rt", + "spin", + "tock-registers", + "x2apic", + "x86", + "x86_64", +] + +[[package]] +name = "polyhal-macro" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8445234620fa3a0886b9cae5d5fa568a6124efb916041628eb9c4011d1a3e8b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "printf-compat" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b002af28ffe3d3d67202ae717810a28125a494d5396debc43de01ee136ac404" +dependencies = [ + "bitflags 1.3.2", + "cstr_core", + "cty", + "itertools", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/procfs.git#0477d4ee50bf00700e507f3f192c499a36d5265f" +dependencies = [ + "log", + "sync", + "vfscore", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ramfs" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/ramfs.git#55d83b65cfc6b3f0c2d83403515c1618a578a99a" +dependencies = [ + "frame_allocator", + "log", + "polyhal", + "sync", + "vfscore", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "raw-cpuid" +version = "11.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" +dependencies = [ + "bitflags 2.4.2", +] + +[[package]] +name = "riscv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9" +dependencies = [ + "critical-section", + "embedded-hal", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "sbi-rt" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c113c53291db8ac141e01f43224ed488b8d6001ab66737b82e04695a43a42b7" +dependencies = [ + "sbi-spec", +] + +[[package]] +name = "sbi-spec" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4027cf9bb591a9fd0fc0e283be6165c5abe96cb73e9f0e24738c227f425377" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "signal" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/signal.git#a03290b18ccd77a999d4c3755b902895079f6ff5" +dependencies = [ + "bit_field", + "bitflags 2.4.2", + "num_enum", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/sync.git#8c5f094d85cd7f4574bb6035c87d94dc5dee3998" +dependencies = [ + "spin", +] + +[[package]] +name = "timestamp" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/timestamp.git#0394ccfa14db1912047a0a3e7e1c38b027856165" + +[[package]] +name = "tock-registers" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vfscore" +version = "0.1.0" +source = "git+https://github.com/Byte-OS/vfscore.git#63092dfae0c3a865ca5dc9292d628e10c6b82392" +dependencies = [ + "bitflags 2.4.2", + "downcast-rs", +] + +[[package]] +name = "virtio-drivers" +version = "0.7.1" +source = "git+https://github.com/rcore-os/virtio-drivers?rev=61ece50#61ece509c40f32c03378a7a037ef9863ed5deba7" +dependencies = [ + "bitflags 2.4.2", + "log", + "zerocopy", +] + +[[package]] +name = "volatile" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" + +[[package]] +name = "x2apic" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbcd582541cbb8ef1dfc24a3c849a64ff074b1b512af723ad90056558d424602" +dependencies = [ + "bit", + "bitflags 1.3.2", + "paste", + "raw-cpuid 10.7.0", + "x86_64", +] + +[[package]] +name = "x86" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "raw-cpuid 10.7.0", +] + +[[package]] +name = "x86_64" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "rustversion", + "volatile", +] + +[[package]] +name = "xmas-elf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f820cc767d65b32eef9d7ce7201448f28501c59edc55d47b71375fea579fc2df" +dependencies = [ + "zero", +] + +[[package]] +name = "zero" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fe21bcc34ca7fe6dd56cc2cb1261ea59d6b93620215aefb5ea6032265527784" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 148ddd2e..f986bb09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,8 @@ -[workspace] -members = [ - # arch - "arch", - - # crates - "crates/console", +[patch] - # modules - "modules/logging", - "modules/panic_handler", +[profile.release] +debug = true - # kernel - "kernel" -] +[workspace] +members = ["kernel"] +resolver = "2" diff --git a/Makefile b/Makefile index e94734f3..94f07d30 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,172 @@ -ARCH := riscv64imac -LOG := info -KERNEL_ELF = target/$(ARCH)-unknown-none-elf/release/kernel +SHELL := /bin/bash +BOARD:= qemu +BIN := +byteos = $(shell kbuild $(1) byteos.yaml $(BIN) $(2)) +byteos_config = $(call byteos,config,get_cfg $(1)) +byteos_env = $(call byteos,config,get_env $(1)) +byteos_meta = $(call byteos,config,get_meta $(1)) +byteos_triple = $(call byteos,config,get_triple $(1)) +NVME := off +NET := off +LOG := error +RELEASE := release +QEMU_EXEC ?= +GDB ?= gdb-multiarch +ARCH := $(call byteos_triple,arch) +ROOT_FS := $(call byteos_config,root_fs) +TARGET := $(call byteos_meta,target) -all: +BUS := device +ifeq ($(ARCH), x86_64) + QEMU_EXEC += qemu-system-x86_64 \ + -machine q35 \ + -kernel $(KERNEL_ELF) \ + -cpu IvyBridge-v2 + BUS := pci +else ifeq ($(ARCH), riscv64) + QEMU_EXEC += qemu-system-$(ARCH) \ + -machine virt \ + -bios $(SBI) \ + -kernel $(KERNEL_BIN) +else ifeq ($(ARCH), aarch64) + QEMU_EXEC += qemu-system-$(ARCH) \ + -cpu cortex-a72 \ + -machine virt \ + -kernel $(KERNEL_BIN) +else ifeq ($(ARCH), loongarch64) + QEMU_EXEC += qemu-system-$(ARCH) -kernel $(KERNEL_ELF) + BUS := pci +else + $(error "ARCH" must be one of "x86_64", "riscv64", "aarch64" or "loongarch64") +endif + +KERNEL_ELF = target/$(TARGET)/$(RELEASE)/kernel +KERNEL_BIN = target/$(TARGET)/$(RELEASE)/kernel.bin +BIN_FILE = byteos.bin +# SBI := tools/rustsbi-qemu.bin +FS_IMG := mount.img +SBI := tools/opensbi-$(BOARD).bin +features:= +K210-SERIALPORT = /dev/ttyUSB0 +K210-BURNER = tools/k210/kflash.py +QEMU_EXEC += -m 1G\ + -nographic \ + -smp 1 \ + -D qemu.log -d in_asm,int,pcall,cpu_reset,guest_errors + +TESTCASE := testcase-$(ARCH) +ifeq ($(NVME), on) +QEMU_EXEC += -drive file=$(FS_IMG),if=none,id=nvm \ + -device nvme,serial=deadbeef,drive=nvm +else +QEMU_EXEC += -drive file=$(FS_IMG),if=none,format=raw,id=x0 + QEMU_EXEC += -device virtio-blk-$(BUS),drive=x0 +endif + +ifeq ($(NET), on) +QEMU_EXEC += -netdev user,id=net0,hostfwd=tcp::6379-:6379,hostfwd=tcp::2222-:2222,hostfwd=tcp::2000-:2000,hostfwd=tcp::8487-:8487,hostfwd=tcp::5188-:5188,hostfwd=tcp::12000-:12000 -object filter-dump,id=net0,netdev=net0,file=packets.pcap \ + -device virtio-net-$(BUS),netdev=net0 +features += net +endif + +ifeq ($(BOARD), k210) +SBI = tools/rustsbi-k210.bin +features += k210 +endif + +all: build +offline: + RUST_BACKTRACE=1 LOG=$(LOG) cargo build $(BUILD_ARGS) --features "$(features)" --offline +# cp $(SBI) sbi-qemu +# cp $(KERNEL_ELF) kernel-qemu + rust-objcopy --binary-architecture=riscv64 $(KERNEL_ELF) --strip-all -O binary os.bin + +fs-img: + @echo "TESTCASE: $(TESTCASE)" + @echo "ROOT_FS: $(ROOT_FS)" + rm -f $(FS_IMG) + dd if=/dev/zero of=$(FS_IMG) bs=1M count=128 + sync +ifeq ($(ROOT_FS), fat32) + mkfs.vfat -F 32 $(FS_IMG) + mkdir mount/ -p + sudo mount $(FS_IMG) mount/ -o uid=1000,gid=1000 + sudo rm -rf mount/* +else ifeq ($(ROOT_FS), ext4_rs) + mkfs.ext4 -b 4096 $(FS_IMG) + mkdir mount/ -p + sudo mount $(FS_IMG) mount/ +else + mkfs.ext4 -F -O ^metadata_csum_seed $(FS_IMG) + mkdir mount/ -p + sudo mount $(FS_IMG) mount/ +endif + sudo cp -rf tools/$(TESTCASE)/* mount/ + sync + sudo umount $(FS_IMG) build: - LOG=$(LOG) cargo build --release + kbuild build byteos.yaml $(BIN) + rust-objcopy --binary-architecture=$(ARCH) $(KERNEL_ELF) --strip-all -O binary $(KERNEL_BIN) + +justbuild: fs-img build + +run: fs-img build + time $(QEMU_EXEC) + +fdt: + @qemu-system-riscv64 -M 128m -machine virt,dumpdtb=virt.out + fdtdump virt.out + +justrun: fs-img + rust-objcopy --binary-architecture=$(ARCH) $(KERNEL_ELF) --strip-all -O binary $(KERNEL_BIN) + $(QEMU_EXEC) -run: build - qemu-system-riscv64 \ - -machine virt \ - -kernel $(KERNEL_ELF) \ - -m 128M \ - -nographic \ - -smp 2 +tftp-build: build + rust-objcopy --binary-architecture=riscv64 $(KERNEL_ELF) --strip-all -O binary $(BIN_FILE) + sudo ./tftp-burn.sh + +k210-build: build + rust-objcopy --binary-architecture=riscv64 $(KERNEL_ELF) --strip-all -O binary $(BIN_FILE) + @cp $(SBI) $(SBI).copy + @dd if=$(BIN_FILE) of=$(SBI).copy bs=131072 seek=1 + @mv $(SBI).copy $(BIN_FILE) + +flash: k210-build + (which $(K`210-BURNER)) || (cd tools && git clone https://github.com/sipeed/kflash.py.git k210) + @sudo chmod 777 $(K210-SERIALPORT) + python3 $(K210-BURNER) -p $(K210-SERIALPORT) -b 1500000 $(BIN_FILE) + python3 -m serial.tools.miniterm --eol LF --dtr 0 --rts 0 --filter direct $(K210-SERIALPORT) 115200 + +debug: fs-img build + @tmux new-session -d \ + "$(QEMU_EXEC) -s -S && echo '按任意键继续' && read -n 1" && \ + tmux split-window -h "$(GDB) $(KERNEL_ELF) -ex 'target remote localhost:1234' -ex 'disp /16i $pc' " && \ + tmux -2 attach-session -d + # $(QEMU_EXEC) -s -S & + # sleep 1 + # $(GDB) $(KERNEL_ELF) \ + # -ex 'target remote localhost:1234' \ + # -ex 'disp /16i $pc' clean: rm -rf target/ + +gdb: + riscv64-elf-gdb \ + -ex 'file $(KERNEL_ELF)' \ + -ex 'set arch riscv:rv64' \ + -ex 'target remote localhost:1234' + +addr2line: + addr2line -sfipe $(KERNEL_ELF) | rustfilt + + +iso: build + cp $(KERNEL_ELF) tools/iso/example + grub-mkrescue -o bootable.iso tools/iso + +boot-iso: iso + qemu-system-x86_64 -cdrom bootable.iso -serial stdio + +.PHONY: all run build clean gdb justbuild iso boot-iso diff --git a/README.json b/README.json new file mode 100644 index 00000000..6fc24e3c --- /dev/null +++ b/README.json @@ -0,0 +1,9 @@ +{ + "name": "ByteOS", + "description": "This is a kernel.", + "authors": [{ + "name": "yfblock", + "email": "321353225@qq.com" + }], + "keywords": ["os", "byteos", "kernel"] +} diff --git a/README.md b/README.md index 07a934ba..1c4054e5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,116 @@ -# 河南科技大学-你说对不队 +# ByteOS -## 内核 ByteOS +## How to use this project. + +Install kbuild. +```shell +cargo install kbuild +``` + +Run with make file. + +```shell +# riscv64 +make BIN=riscv64-qemu run +# aarch64 +make BIN=aarch64-qemu run +# x86_64 +make BIN=x86_64-qemu run +# loongarch64 +make BIN=loongarch64-qemu run +``` + +You can find available modules using the following command. + +```shell +byteos patch list + +# Download and patch in Cargo.toml +byteos patch add arch + +# remove patch and delete folder +byteos patch remove arch +``` + +## byteos.yaml + +> byteos.yaml is a configuration file for the ByteOS. + +You can change the config in this file. For example, you want to use the ext4 fielsystem. + +Set the root_fs to 'ext4' or 'ext4_rs' will change the root_fs from 'fat32' to 'ext4'. + +The 'ext4' and 'ext4_rs' are the different implementation of the ext4. + +TIPS: Make ensure that the mkefs version of your system lower than 1.70. If not, you have to use another argument to build the ext4 image. + + +## Kernel struct Design + +> ByteOS is a posix-compatible kernel. +> +> If you are interested in this project, please contact me. +> +> email: 321353225@qq.com qq: 321353225 + +```plain +crates --> arch --> modules --> kernel +``` + +## TODO List +- [x] higher half kernel +- [x] Modular skeleton +- [x] global allocator +- [x] RTC device support +- [x] Timestamp --> actual Date/Time [timestamp crate](crates/timestamp/) +- [x] frame allocator, use bit_field to store page usage +- [x] Interrupt support +- [x] backtrace support +- [x] timer interrupt support +- [x] page mapping support +- [x] get devices info and memory info from device_tree +- [x] VIRTIO blk device support +- [x] Add a banner for os. use tool [banner generation tool](http://patorjk.com/software/taag/#p=display&f=Big&t=ByteOS) +- [x] vfs support +- [x] fatfs support +- [x] fs mount support (a temporary solution) +- [x] ramfs support +- [x] devfs support +- [x] async/await support (simple version) +- [x] process support +- [x] VIRTIO net device support +- [ ] smp support +- [ ] desktop support. eg: dwm, hyprland. + +## Program support + + +tools/final2023: + +- libctest +- libcbench +- busybox +- lua +- lmbench +- iozone +- iperf3 +- nerperf +- cyclic +- unixbench + +tools/gcc + +- gcc +- redis-server +- ssh-simple +- http-server + +You can change the `TESTCASE` in the makefile to change the target. You can run other program in the sh or change the default program in the `kernel/src/tasks/initproc.rs` file. + +## run busybox sh on qemu platform + +```bash +make run BOARD=qemu LOG=info NET=off +``` + +Changing 'LOG=info' to 'LOG=error' if you don't need any info output. diff --git a/arch/Cargo.toml b/arch/Cargo.toml deleted file mode 100644 index 2e24d177..00000000 --- a/arch/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "arch" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log = "0.4.16" \ No newline at end of file diff --git a/arch/src/lib.rs b/arch/src/lib.rs deleted file mode 100644 index c352cd48..00000000 --- a/arch/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![no_std] -#![no_main] - -#[macro_use] -extern crate log; - -mod riscv; - -#[cfg(target_arch = "riscv64")] -pub use riscv::*; \ No newline at end of file diff --git a/arch/src/riscv/entry/entry.S b/arch/src/riscv/entry/entry.S deleted file mode 100644 index f28b840b..00000000 --- a/arch/src/riscv/entry/entry.S +++ /dev/null @@ -1,47 +0,0 @@ - .section .text.entry - .globl _start -_start: - # # 1. set sp - # # sp = bootstack + (hartid + 1) * 0x10000 - # add t0, a0, 1 - # slli t0, t0, 14 - # lui sp, %hi(bootstack) - # add sp, sp, t0 - - # # 2. enable paging - # # satp = (8 << 60) | PPN(boot_page_table_sv39) - # lui t0, %hi(boot_page_table_sv39) - # li t1, 0xffffffffc0000000 - 0x80000000 - # sub t0, t0, t1 - # srli t0, t0, 12 - # li t1, 8 << 60 - # or t0, t0, t1 - # csrw satp, t0 - # sfence.vma - - # # 3. jump to rust_main (absolute address) - # lui t0, %hi(rust_main) - # addi t0, t0, %lo(rust_main) - # jr t0 - - la sp, bootstacktop - call rust_main - - .section .bss.stack - .align 12 # page align - .global bootstack -bootstack: - .space 4096 * 4 * 8 - .global bootstacktop -bootstacktop: - - .section .data - .align 12 # page align -boot_page_table_sv39: - # 0x00000000_80000000 -> 0x80000000 (1G) - # 0xffffffff_c0000000 -> 0x80000000 (1G) - .quad 0 - .quad 0 - .quad (0x80000 << 10) | 0xcf # VRWXAD - .zero 8 * 508 - .quad (0x80000 << 10) | 0xcf # VRWXAD \ No newline at end of file diff --git a/arch/src/riscv/entry/mod.rs b/arch/src/riscv/entry/mod.rs deleted file mode 100644 index 00fe13aa..00000000 --- a/arch/src/riscv/entry/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -use core::arch::global_asm; - -global_asm!(include_str!("entry.S")); \ No newline at end of file diff --git a/arch/src/riscv/mod.rs b/arch/src/riscv/mod.rs deleted file mode 100644 index 4ce04924..00000000 --- a/arch/src/riscv/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod entry; -mod sbi; - -pub use sbi::*; - -#[no_mangle] -extern "C" fn rust_main(hartid: usize) { - extern "Rust" { - fn main(hartid: usize); - } - - unsafe { main(hartid); } - - shutdown(); -} \ No newline at end of file diff --git a/arch/src/riscv/sbi.rs b/arch/src/riscv/sbi.rs deleted file mode 100644 index 11be026e..00000000 --- a/arch/src/riscv/sbi.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! 调用 Machine 层的操作 -// 目前还不会用到全部的 SBI 调用,暂时允许未使用的变量或函数 -#![allow(unused)] - -use core::arch::asm; - -const SBI_SET_TIMER: usize = 0; -const SBI_CONSOLE_PUT_CHAR: usize = 1; -const SBI_CONSOLE_GET_CHAR: usize = 2; -const SBI_CLEAR_IPI: usize = 3; -const SBI_SEND_IPI: usize = 4; -const SBI_REMOTE_FENCE_I: usize = 5; -const SBI_REMOTE_SFENCE_VMA: usize = 6; -const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; -const SBI_SHUTDOWN: usize = 8; - -// SBI 调用 -fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> i32 { - let mut ret; - unsafe { - asm!("ecall", - in("a7") which, - inlateout("a0") arg0 as i32 => ret, - in("a1") arg1, - in("a2") arg2); - } - ret -} - -/// 设置定时器 -pub fn set_timer(time: usize) { - sbi_call(SBI_SET_TIMER, time, 0, 0); -} - -/// 输出一个字符到屏幕 -pub fn console_putchar(ch: u8) { - sbi_call(SBI_CONSOLE_PUT_CHAR, ch as usize, 0, 0); -} - -/// 获取输入 -pub fn console_getchar() -> char { - sbi_call(SBI_CONSOLE_GET_CHAR, 0, 0, 0) as u8 as char -} - - -/// 调用 SBI_SHUTDOWN 来关闭操作系统(直接退出 QEMU) -pub fn shutdown() -> ! { - sbi_call(SBI_SHUTDOWN, 0, 0, 0); - unreachable!() -} - -#[repr(C)] -pub struct SbiRet { - /// Error number - pub error: usize, - /// Result value - pub value: usize, -} - -pub const EXTENSION_BASE: usize = 0x10; -pub const EXTENSION_TIMER: usize = 0x54494D45; -pub const EXTENSION_IPI: usize = 0x735049; -pub const EXTENSION_RFENCE: usize = 0x52464E43; -pub const EXTENSION_HSM: usize = 0x48534D; -pub const EXTENSION_SRST: usize = 0x53525354; - -const FUNCTION_HSM_HART_START: usize = 0x0; -const FUNCTION_HSM_HART_STOP: usize = 0x1; -const FUNCTION_HSM_HART_GET_STATUS: usize = 0x2; -const FUNCTION_HSM_HART_SUSPEND: usize = 0x3; - -#[inline(always)] -fn sbi_call_3(extension: usize, function: usize, arg0: usize, arg1: usize, arg2: usize) -> SbiRet { - let (error, value); - unsafe { - asm!( - "ecall", - in("a0") arg0, in("a1") arg1, in("a2") arg2, - in("a6") function, in("a7") extension, - lateout("a0") error, lateout("a1") value, - ) - } - SbiRet { error, value } -} - -pub fn hart_suspend(suspend_type: u32, resume_addr: usize, opaque: usize) -> SbiRet { - sbi_call_3( - EXTENSION_HSM, - FUNCTION_HSM_HART_SUSPEND, - suspend_type as usize, - resume_addr, - opaque, - ) -} \ No newline at end of file diff --git a/byteos b/byteos new file mode 100755 index 00000000..cfcd32ac --- /dev/null +++ b/byteos @@ -0,0 +1,32 @@ +#!/usr/bin/env -S deno --ext=ts --allow-run --allow-read --allow-env + +import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"; +import { cliCommand as buildCommand } from './scripts/cli-build.ts'; +import { cliCommand as qemuCommand } from './scripts/cli-qemu.ts'; +import { logLevelEnum, archEnum } from './scripts/cli-types.ts'; +import { parse } from "jsr:@std/yaml"; + +const command = new Command() + .name("byteos") + .version("0.1.0") + .description("Building tools for the byteos.") + + .globalType("log-level", logLevelEnum) + .globalOption("-l, --log-level ", "Set Log Level", { default: 'info' }) + .globalType("architecture", archEnum) + .globalOption("-a, --arch [arch:architecture]", "Set the architecture", { required: true }) + + // Sub Command build + .command("build", buildCommand) + .command("qemu", qemuCommand); + +// parse yaml file +const data = parse(new TextDecoder("utf-8").decode(await Deno.readFile("byteos.yaml"))); +console.log(data); + +try { + // Parse the command. + await command.parse(Deno.args); +} catch (e) { + console.error("Error", e); +} diff --git a/byteos.yaml b/byteos.yaml new file mode 100644 index 00000000..534045c0 --- /dev/null +++ b/byteos.yaml @@ -0,0 +1,44 @@ + +global: + configs: + board: "qemu" + # Available are fat32, ext4 and ext4_rs. + # root_fs: "fat32" + root_fs: "ext4_rs" + env: + HEAP_SIZE: "0x0180_0000" + MOUNT_IMG_PATH: "mount.img" + +bin: + riscv64-qemu: + target: "riscv64gc-unknown-none-elf" + configs: + driver: "kvirtio,kgoldfish-rtc,ns16550a" + riscv64-vf2: + target: "riscv64imac-unknown-none-elf" + configs: + board: "visionfive2" + driver: "kramdisk" + x86_64-qemu: + target: "x86_64-unknown-none" + configs: + driver: "kvirtio,kgoldfish-rtc,ns16550a" + x86_64-generic: + target: "x86_64-unknown-none" + configs: + driver: "kramdisk,kgoldfish-rtc,ns16550a" + aarch64-qemu: + target: "aarch64-unknown-none-softfloat" + configs: + driver: "kvirtio,kgoldfish-rtc,ns16550a" + loongarch64-qemu: + target: "loongarch64-unknown-none" + build_std: "core,alloc" + configs: + driver: "kramdisk" + loongarch64-2k1000: + target: "loongarch64-unknown-none" + build_std: "core,alloc" + configs: + driver: "kramdisk" + board: "2k1000" diff --git a/config/cv1811h.toml b/config/cv1811h.toml new file mode 100644 index 00000000..586cbbb0 --- /dev/null +++ b/config/cv1811h.toml @@ -0,0 +1,14 @@ +# TIPS: This is a config file for cv1811h platform. + +# driver list +drivers = [ + "general-plic", + "ns16550a", + "kcvitek-sd", +] + +cfgs = [ + "c906" +] + +features = [] diff --git a/config/k210.toml b/config/k210.toml new file mode 100644 index 00000000..73b1bbd0 --- /dev/null +++ b/config/k210.toml @@ -0,0 +1,11 @@ +# TIPS: This is a config file for qemu-system-riscv64 platform. + +# driver list +drivers = [ + "kvirtio", + "k210-sdcard", + "general-plic", + "ns16550a", +] + +ld_file = "linker-k210.ld" diff --git a/config/linker-general.ld b/config/linker-general.ld new file mode 100644 index 00000000..007d9e3b --- /dev/null +++ b/config/linker-general.ld @@ -0,0 +1,50 @@ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0xffffffc080200000; +__ENTRY_ADDR = 0x80200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text ALIGN(4K): AT(__ENTRY_ADDR) { + stext = .; + *(.text.entry) + *(.text .text.*) + etext = .; + } + + .sigtrx ALIGN(4K): { + *(.sigtrx .sigtrx.*) + } + + .rodata ALIGN(4K): { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data ALIGN(4K): { + . = ALIGN(4K); + *(.data.prepage .data.prepage.*) + . = ALIGN(4K); + _sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + _edata = .; + } + + .bss ALIGN(4K): { + *(.bss.stack) + _sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + _ebss = .; + } + + PROVIDE(end = .); +} \ No newline at end of file diff --git a/.cargo/linker-riscv.ld b/config/linker-k210.ld similarity index 62% rename from .cargo/linker-riscv.ld rename to config/linker-k210.ld index 76dfd562..4cf17b54 100644 --- a/.cargo/linker-riscv.ld +++ b/config/linker-k210.ld @@ -1,13 +1,9 @@ -/* 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 = 0xffffffffc0200000; */ -BASE_ADDRESS = 0x80200000; +BASE_ADDRESS = 0xffffffc080020000; + +__ENTRY_ADDR = 0x80020000; SECTIONS { @@ -15,25 +11,25 @@ SECTIONS . = BASE_ADDRESS; start = .; - .text : { + .text ALIGN(4K): AT(__ENTRY_ADDR) { stext = .; *(.text.entry) - _copy_user_start = .; - *(.text.copy_user) - _copy_user_end = .; *(.text .text.*) . = ALIGN(4K); etext = .; } - .rodata : { + .rodata ALIGN(4K): { srodata = .; *(.rodata .rodata.*) . = ALIGN(4K); erodata = .; } - .data : { + .data ALIGN(4K): { + . = ALIGN(4K); + *(.data.prepage) + . = ALIGN(4K); sdata = .; *(.data .data.*) *(.sdata .sdata.*) @@ -45,6 +41,7 @@ SECTIONS } .bss : { + *(.bss.stack) sbss = .; *(.bss .bss.*) *(.sbss .sbss.*) diff --git a/config/linker-x86_64.ld b/config/linker-x86_64.ld new file mode 100644 index 00000000..606fb93d --- /dev/null +++ b/config/linker-x86_64.ld @@ -0,0 +1,54 @@ +OUTPUT_ARCH(x86_64) +ENTRY(_start) + +/* BASE_ADDRESS = 0xffffffc000020000; */ +BASE_ADDRESS = 0xffffff8000200000; + +__ENTRY_ADDR = 0x200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + _skernel = .; + + .text ALIGN(4K): AT(__ENTRY_ADDR) { + stext = .; + *(.text.boot) + *(.text.entry) + *(.text .text.*) + etext = .; + } + + .sigtrx ALIGN(4K): { + *(.sigtrx .sigtrx.*) + } + + .rodata ALIGN(4K): { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data ALIGN(4K): { + . = ALIGN(4K); + *(.data.prepage .data.prepage.*) + . = ALIGN(4K); + _sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + _edata = .; + } + + .bss ALIGN(4K): { + *(.bss.stack) + _sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + _ebss = .; + } + + PROVIDE(end = .); +} \ No newline at end of file diff --git a/config/qemu.toml b/config/qemu.toml new file mode 100644 index 00000000..3332875f --- /dev/null +++ b/config/qemu.toml @@ -0,0 +1,14 @@ +# TIPS: This is a config file for qemu-system-riscv64 platform. + +# driver list +drivers = [ + "kvirtio", + "kgoldfish-rtc", + "general-plic", + "ns16550a", + # "knvme", +] + +features = [ + "nvme" +] diff --git a/crates/console/Cargo.toml b/crates/console/Cargo.toml deleted file mode 100644 index 3a35996f..00000000 --- a/crates/console/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "console" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/crates/console/src/lib.rs b/crates/console/src/lib.rs deleted file mode 100644 index 1ef61095..00000000 --- a/crates/console/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -#![no_std] - diff --git "a/docs/ByteOS\350\256\276\350\256\241\345\210\206\344\272\253.pptx" "b/docs/ByteOS\350\256\276\350\256\241\345\210\206\344\272\253.pptx" new file mode 100644 index 00000000..e4f056d7 Binary files /dev/null and "b/docs/ByteOS\350\256\276\350\256\241\345\210\206\344\272\253.pptx" differ diff --git a/docs/Devfs.md b/docs/Devfs.md new file mode 100644 index 00000000..66324610 --- /dev/null +++ b/docs/Devfs.md @@ -0,0 +1,139 @@ +# Devfs + +DevFS(Device Filesystem)是一个虚拟文件系统,用于在Linux内核中表示和访问设备。它提供了一种以文件的形式来访问和操作设备的机制,使得设备可以像文件一样被读取、写入和控制。 + +在DevFS中,每个设备都被表示为文件节点,位于特定的目录结构中。这些文件节点可以通过访问标准的文件I/O接口来进行读取和写入。同时,DevFS还提供了一组特殊的文件节点,用于设备的控制和配置。 + +以下是DevFS的一些重要特点: + +1. 设备表示:DevFS以一种层次结构的方式表示设备,将其组织为目录和文件的形式。每个设备都被表示为一个文件节点,可以通过路径来访问。 +2. 设备访问:通过标准的文件I/O接口(如`open`、`read`、`write`、`close`)来访问和操作设备文件节点。这使得设备可以像普通文件一样进行读写操作。 +3. 设备控制:除了设备文件节点,DevFS还提供了一些特殊的文件节点,用于设备的控制和配置。例如,可以使用这些文件节点来修改设备的属性、发送控制命令或查询设备状态。 +4. 动态更新:DevFS可以根据系统中当前连接的设备动态更新其目录结构。当设备被插入或移除时,DevFS会相应地添加或删除相应的设备文件节点。 +5. 虚拟文件系统:DevFS作为一个虚拟文件系统存在,不直接映射到物理存储设备上。它仅在内核中存在,并提供了一个抽象层,将设备表示为文件。 + +DevFS为设备提供了一种统一的访问机制,将设备的读写和控制操作以文件的形式暴露给用户空间。这种设计使得设备的操作更加灵活和易用,并与现有的文件和文件系统相关工具无缝集成。 + +以下是**ByteOS**中Devfs的实现: + +``` +├── Cargo.toml +└── src + ├── cpu_dma_latency.rs //cpuDMA延迟配置节点 + ├── lib.rs //主要实现 + ├── null.rs //空设备节点 + ├── rtc.rs //RTC设备节点 + ├── sdx.rs //存储设备节点 + ├── shm.rs //共享内存节点 + ├── tty.rs //终端设备访问节点 + ├── urandom.rs //随机数读取节点 + └── zero.rs //全零数据节点 +``` + +CPU DMA延迟节点 + +```rust +pub struct CpuDmaLatency; + +impl INodeInterface for CpuDmaLatency { + fn readat(&self, _offset: usize, buffer: &mut [u8]) -> VfsResult { + buffer.fill(0); + if buffer.len() > 1 { + buffer[0] = 1; + } + Ok(buffer.len()) + } + + fn writeat(&self, _offset: usize, buffer: &[u8]) -> VfsResult { + Ok(buffer.len()) + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + ... + Ok(()) + } +} +``` + +在该实现中,我们定义了一个名为`CpuDmaLatency`的结构体,用于表示CPU DMA延迟节点。这个结构体实现了`INodeInterface`特性,表明它是一个文件节点接口的实现。 + +在结构体的实现中,有几个方法被重写了: + +1. `readat`方法:该方法用于从节点中读取数据。在这个具体的实现中,它将缓冲区(`buffer`)填充为零,并将首字节设置为1(如果缓冲区长度大于1)。最后,它返回读取的字节数。 +2. `writeat`方法:该方法用于向节点中写入数据。在这个具体的实现中,它简单地返回写入的字节数。 +3. `stat`方法:该方法用于获取节点的统计信息。在这个具体的实现中,它设置了一些`Stat`结构体中的字段,例如设备号(`dev`)、节点号(`ino`)、访问模式(`mode`)、链接计数(`nlink`)、用户ID(`uid`)、组ID(`gid`)等。注意,其中一些字段被标记为`TODO`,表示需要根据实际情况进行填充。最后,它返回一个空的`VfsResult`表示成功。 + +这个实现中的方法提供了对CPU DMA延迟节点的常见操作,包括读取、写入和获取统计信息等。 + +其余节点的实现与此类似。 + +以下是Devfs的主要实现 + +```rust +impl INodeInterface for DevDirContainer { + fn open(&self, name: &str, _flags: vfscore::OpenFlags) -> VfsResult> { + self.inner + .map + .get(name) + .map(|x| x.clone()) + .ok_or(VfsError::FileNotFound) + } + + fn read_dir(&self) -> VfsResult> { + Ok(self + .inner + .map + .iter() + .map(|(name, _)| DirEntry { + filename: name.to_string(), + len: 0, + file_type: FileType::Device, + }) + .collect()) + } + + fn stat(&self, stat: &mut vfscore::Stat) -> VfsResult<()> { + ... + Ok(()) + } + + fn metadata(&self) -> VfsResult { + Ok(vfscore::Metadata { + filename: "dev", + inode: 0, + file_type: FileType::Directory, + size: 0, + childrens: self.inner.map.len(), + }) + } + + fn getdents(&self, buffer: &mut [u8]) -> VfsResult { + ... + Ok(ptr - buf_ptr) + } +} +``` + +上述代码实现了`DevDirContainer`结构体对`INodeInterface` trait的方法进行了实现: + +- `open()`方法用于打开指定名称的设备节点。它会在`inner`的映射中查找对应名称的设备节点,并返回它的克隆。如果找不到对应名称的设备节点,则返回`FileNotFound`错误。 + +- `read_dir()`方法用于读取目录内容。它会遍历`inner`的映射中的每个设备节点,并将设备节点的名称、长度、文件类型等信息封装为`DirEntry`结构体,最终返回一个包含所有`DirEntry`的`Vec`。此处由于是虚拟设备文件系统,因此每个设备节点的长度都被设置为0,并且文件类型为`FileType::Device`。 + +- `stat()`方法用于获取设备节点的元数据信息。它会将各种元数据信息填充到提供的`stat`结构体中,包括设备号、索引节点号、访问模式、链接数、所有者ID、大小、块大小、块数等。此处只是进行了一些默认值的填充。 + +- `metadata()`方法用于获取设备节点的元数据。它会返回一个`Metadata`结构体,包含文件名、索引节点号、文件类型、大小和子节点数量等信息。在这里,文件名被设置为"dev",索引节点号为0,文件类型为`FileType::Directory`,大小为0,子节点数量为`inner.map`的长度。 + +- `getdents()`方法用于获取目录的目录项。它会将目录中的每个设备节点的信息填充到提供的缓冲区中,以`Dirent64`的结构体形式表示。每个`Dirent64`包含了设备节点的相关信息,如索引节点号、偏移量、记录长度、文件类型和文件名等。此处使用了`unsafe`代码块来操作原始指针,将设备节点的名称拷贝到缓冲区中,并更新指针位置和计数器。最后返回已填充数据的字节数。 + +这些方法的实现使得`DevDirContainer`成为一个可操作的虚拟设备文件系统目录,可以进行打开设备节点、读取目录内容、获取元数据和目录项等操作。 + +DevFS文件系统的实现具有以下亮点: + +1. 设备节点映射:`DevDir`使用`BTreeMap`来存储设备节点的名称和对应的`INodeInterface`实现的Arc指针。这种映射关系允许快速查找和访问设备节点。 +2. 文件系统接口:`DevFS`实现了`FileSystem` trait,提供了统一的文件系统操作接口。通过实现`root_dir()`、`name()`等方法,使得DevFS可以与其他文件系统一起使用,并符合通用的文件系统操作规范。 +3. 高度可定制化:`DevDir`的构造函数提供了一种灵活的方式来添加设备节点。通过调用`add()`方法,可以向DevDir中动态添加新的设备节点,使得文件系统的内容可以根据需要进行定制和扩展。 +4. 安全性:使用`Arc`和`Mutex`来处理并发访问的问题。`DevFS`和`DevDirContainer`都使用了`Arc`来进行引用计数和共享所有权,以确保线程安全性。同时,`DevDirContainer`中的`dents_off`字段使用了`Mutex`来处理目录项偏移量的并发访问。 +5. 虚拟设备文件系统:DevFS是一个虚拟的设备文件系统,它提供了一种抽象的方式来表示设备节点。通过将不同类型的设备节点添加到`DevDir`中,可以模拟各种设备的存在和访问。 + +这些特点使得该DevFS文件系统的实现具有灵活性、可扩展性和安全性。它提供了一种简单而强大的方式来管理和访问设备节点,并能够方便地与其他文件系统进行集成和使用。 \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..a4359e24 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,42 @@ +# README + +## 项目文件结构 + +[项目结构](项目结构.md) + +[内核部分文件结构](内核部分文件结构.md) + +[creates部分文件结构](creates部分文件结构.md) + +[modules部分文件结构](modules部分文件结构.md) + +[drivers部分文件结构](drivers部分文件结构.md) + +## 内核设计 + +[内核输出](内核输出.md) + +[内核半高核](内核半高核.md) + +## 华山派SD卡驱动设计 + +[华山派开发板SD卡驱动设计](华山派开发板SD卡驱动设计.md) + +## 文件系统 + +[虚拟文件系统](虚拟文件系统.md) + +[文件系统](文件系统.md) + +[Devfs](Devfs.md) + +[procfs](procfs.md) + +[ramfs](ramfs.md) + +## 内存管理 + +[页帧分配器](页帧分配器.md) + +[内存分配器](内存分配器.md) + diff --git "a/docs/Ramfs\346\200\235\350\200\203.md" "b/docs/Ramfs\346\200\235\350\200\203.md" new file mode 100644 index 00000000..47b0681b --- /dev/null +++ "b/docs/Ramfs\346\200\235\350\200\203.md" @@ -0,0 +1,44 @@ +# Ramfs 思考 + +## 思路是什么? + +Ramfs 为例: 兼顾 `mount`, 无需设置 `mount point` 吗? +只需要在初始化的时候设置好相对于文件系统的 path 即可, + +那如何判断 `mount` 的问题? +可以在 `fs` `item` 里指向文件系统 本身,然后做到这个? + +觉得可以 所以 `vfs::FileSystem::root_dir` `mount_point` 添加是不是有点多余 +但是如果有多个挂载点的话怎么办 +所以也许 `mount_point` 可以设置成一个 `Arc` 的信息,然后在每一个节点保存 + +如果没有 `mount_point` 怎么办?直接设置一个? + +`Linux` 的 `/var/run` 机制是怎么做到的?到底是挂载了还是没挂载? + +利用 `root_dir` 传递参数这种机制,可以保证在 `fatfs-shim` 里取消 `fatfs` `new` 时传递的文件系统相关参数 +改为在 `root_dir` 里传递一个 `MountedInfo` 结构,里面包一层 `Arc` +目前构想的结构 +```rust +struct MountedInfo { + path: Arc, + fs: Arc +} +``` + +利用这种机制就可以 在 `open` 文件的时候判断是否有文件夹 `mounted` 在这个文件夹下 + +但是 `offset` ? 这个是问题 + +所以还需要 `inner` 这个机制 +文件需要 `inner` 和 `container`(或者就是文件名) +`inner` 保存在 `RamFsDir` 里,然后创建文件时直接创建一层壳,`inner` 直接 `clone` +`dir` 同理 +但是出现一个问题,原来在 `dir` 的保存信息是 `Vec>`, +更新结构过后需要设计一种新的结构 或者使用 `enum` +```rust +pub enum RamItem { + File(RamFsFile), + Dir(RamFsDir), +} +``` diff --git a/docs/async.md b/docs/async.md new file mode 100644 index 00000000..ee537ce8 --- /dev/null +++ b/docs/async.md @@ -0,0 +1,3 @@ +# Async 编程 + +由于使用了 `Rust` 的 `async` 机制,所以动态的 `kill task` 也成为了必要,因此在编程的时候尽量避免在 `await` 之前对 `task` 进行枷锁,防止出现死锁的情况。 \ No newline at end of file diff --git "a/docs/creates\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/creates\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" new file mode 100644 index 00000000..02d4d7a8 --- /dev/null +++ "b/docs/creates\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" @@ -0,0 +1,24 @@ +# creates部分文件结构 + +``` +├── backtrace //信息回溯的相关实现 +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +├── cv1811-sd //支持华山派cv1811h的SD卡驱动 +│   ├── Cargo.toml +│   └── src +│   ├── consts.rs +│   ├── lib.rs +│   └── utils.rs +├── timestamp //时间戳功能 +│   ├── Cargo.toml +│   ├── README.md +│   └── src +│   └── lib.rs +└── vfscore //虚拟文件系统 + ├── Cargo.toml + └── src + └── lib.rs +``` + diff --git "a/docs/drivers\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/drivers\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" new file mode 100644 index 00000000..c1673a51 --- /dev/null +++ "b/docs/drivers\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" @@ -0,0 +1,69 @@ +# drivers部分文件结构 + +``` +├── k210-sdcard //支持k210的SD卡驱动 +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +├── kcvitek-sd //kcvitek-sd驱动 +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +├── kgoldfish-rtc //RTC设备驱动 +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +├── knvme //KNVME驱动 +│   ├── Cargo.toml +│   └── src +│   └── lib.rs +└── kvirtio //虚拟IO驱动 + ├── Cargo.toml + └── src + ├── lib.rs + ├── virtio_blk.rs + ├── virtio_impl.rs + └── virtio_net.rs +``` + +我们在内核中使用 `Linke` 的库实现了对于驱动的简单组合,在一些情况下,我们需要构建针对某个硬件的 OS,而且只需要部分驱动,这个时候我们就可以通过在ByteOS中的 `link` 设计,实现对于驱动的组合。 + +下面是我们 `kernel/src/modules.rs` 中的内容。 +```rust +#[allow(unused_imports)] +use kheader::macros::module_use; + +module_use!(kvirtio); +#[cfg(feature = "nvme")] +module_use!(knvme); + +module_use!(kgoldfish_rtc); + +#[cfg(feature = "board-k210")] +module_use!(k210_sdcard); +#[cfg(feature = "board-cv1811h")] +module_use!(kcvitek_sd); +``` +如果我们需要使用某个驱动,我们可以使用 `module_use!` 宏进行驱动的注入。所有的注入的驱动会在检查设备树之前进行挂载。如果我们需要追加设备树上没有的设备也可以通过这个功能进行注入。 + +所有需要注入的驱动里面需要利用 `driver_define!` 宏进行初始化函数和结构的定义。 + +将设备挂载到设备树上。 + +```rust +driver_define!("cvitek,mars-sd", { + DRIVER_REGS.lock().insert("cvitek,mars-sd", init_rtc); + None +}); +``` + +直接注入驱动 + +```rust +driver_define!(DRIVERS_INIT, { + info!("init k210 sdcard"); + Some(Arc::new(SDCardWrapper::new())) +}); +``` + +如果我们需要直接 \ No newline at end of file diff --git a/docs/kcov.md b/docs/kcov.md new file mode 100644 index 00000000..4733ddcc --- /dev/null +++ b/docs/kcov.md @@ -0,0 +1,226 @@ +# KCov 实现 + +> TIPS: 具体请参考 syzkaller 分支. + +Kcov 是一个代码覆盖率工具,用于评估测试套件对代码的覆盖程度。它可以帮助开发人员确定他们的测试用例是否足够全面,是否能够覆盖代码中的所有分支和路径。 + +Kcov 可以跟踪程序执行过程中哪些代码行被执行了,以及哪些代码行没有被执行到。它通过插桩(instrumentation)的方式,将额外的代码注入到被测试的程序中,以便收集覆盖率信息。 + +使用 Kcov,您可以获得以下信息: + +代码行覆盖率:Kcov 可以告诉您在测试过程中有多少代码行被执行了,以及这些执行的代码行所占总代码行数的百分比。 + +分支覆盖率:Kcov 还可以提供关于代码中条件语句的分支覆盖信息。它可以告诉您在测试过程中有多少条件分支被覆盖了,以及这些覆盖的分支所占总分支数的百分比。 + +这些覆盖率信息可以帮助开发人员评估测试用例的质量,并确定是否需要编写更多的测试用例来增加代码覆盖率。 + +因此我们使用 kcov 的使用例程来作为测试用例,检测我们的 kcov 实现。 + +[https://www.kernel.org/doc/html/latest/dev-tools/kcov.html](https://www.kernel.org/doc/html/latest/dev-tools/kcov.html) + +```c +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) +#define KCOV_ENABLE _IO('c', 100) +#define KCOV_DISABLE _IO('c', 101) +#define COVER_SIZE (64<<10) + +#define KCOV_TRACE_PC 0 +#define KCOV_TRACE_CMP 1 + +int main(int argc, char **argv) +{ + int fd; + unsigned long *cover, n, i; + + /* A single fd descriptor allows coverage collection on a single + * thread. + */ + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + /* Setup trace mode and trace size. */ + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + /* Mmap buffer shared between kernel- and user-space. */ + cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + /* Enable coverage collection on the current thread. */ + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC)) + perror("ioctl"), exit(1); + /* Reset coverage from the tail of the ioctl() call. */ + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + /* Call the target syscall call. */ + read(-1, NULL, 0); + /* Read number of PCs collected. */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) + printf("0x%lx\n", cover[i + 1]); + /* Disable coverage collection for the current thread. After this call + * coverage can be enabled for a different thread. + */ + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + /* Free resources. */ + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; +} +``` + +我们构造的 kcov 文件如下 + +```rust + +pub struct Fuz{ + inner: Mutex<(usize, usize)> +} + +impl Fuz { + pub fn new() -> Arc { + Arc::new(Self { + inner: Mutex::new((0, 0)) + }) + } +} + +impl INodeInterface for Fuz { + fn readat(&self, _offset: usize, _buffer: &mut [u8]) -> vfscore::VfsResult { + Ok(0) + } + + fn writeat(&self, _offset: usize, _buffer: &[u8]) -> vfscore::VfsResult { + Ok(0) + } + + fn ioctl(&self, command: usize, _arg: usize) -> vfscore::VfsResult { + log::info!("ioctl: {} arg: {}", command, _arg); + const ENABLE_FUZ: usize = 25444; + const DISABLE_FUZ: usize = 25445; + const INIT_FUZ_TRACE: usize = 2148033281; + match command { + ENABLE_FUZ => { + let (addr, len) = *self.inner.lock(); + enable_fuz(addr, len); + Ok(0) + } + DISABLE_FUZ => { + disable_fuz(); + Ok(0) + } + INIT_FUZ_TRACE => { + let (addr, len) = *self.inner.lock(); + init_fuz(addr, len); + Ok(0) + } + _ => Err(vfscore::VfsError::NotSupported) + } + } + + fn after_mmap(&self, _addr: usize, _size: usize) -> vfscore::VfsResult<()> { + log::info!("after_mmap: {}, size: {}", _addr, _size); + *self.inner.lock() = (_addr, _size); + Ok(()) + } +} +``` + +我们在内核的 init 线程中将 kcov 文件挂载在 ByteOS 的文件树上。然后利用 Fuz_records 进行 Fuz 数据的记录。 + +``` rust +pub static IS_FUZZING: AtomicBool = AtomicBool::new(false); + +pub struct FuzzItem { + pub ip: usize, + pub tp: usize, + pub arg1: usize, + pub arg2: usize, +} + +pub static FUZ_RECORDS: Mutex<(usize, usize)> = Mutex::new((0, 0)); + +pub fn enable_fuz(addr: usize, len: usize) { + IS_FUZZING.store(true, core::sync::atomic::Ordering::Relaxed); + log::info!("enable_fuzing: {:#x}, {:#x}", addr, len); + *FUZ_RECORDS.lock() = (addr, len); +} + +pub fn disable_fuz() { + IS_FUZZING.store(false, core::sync::atomic::Ordering::Relaxed); + *FUZ_RECORDS.lock() = (0, 0); +} + +pub fn init_fuz(addr: usize, len: usize) { + *FUZ_RECORDS.lock() = (addr, len); +} + +pub fn write_fuz(data: &str) { + if !IS_FUZZING.fetch_or(false, core::sync::atomic::Ordering::Relaxed) { + return; + } + let ra: usize; + unsafe { + asm!("", out("ra") ra) + } + // log::error!("ra: {:#x}", ra); + let (addr, len) = *FUZ_RECORDS.lock(); + if addr == 0 || len == 0 { + return; + } + unsafe { + let n = addr as *mut usize; + let wptr = (addr as *mut usize).add(*n + 1); + if wptr as usize >= addr + len { + return; + } + wptr.write_volatile(ra); + *n +=1; + } + println!("{}", data); +} + +pub macro fuz() { + fn f() {} + fn type_name_of(_: T) -> &'static str { + core::any::type_name::() + } + let name = type_name_of(f); + $crate::kcov::write_fuz(&format!("{}\n{}: {}", &name[..name.len() - 16], file!(), line!())) +} +``` + +在内核的系统调用和需要 fuz 的地方加上 `fuz` 宏,然后在开启 `kcov` 后就可以进行记录。实现简单的 `kcov`. + +我们在我们的 Makefile 文件中添加了 make addrline 指令,可以将 `kcov` 记录的地址进行转换,实现类似下面的输出。 + +``` +SyS_read +fs/read_write.c:562 +__fdget_pos +fs/file.c:774 +__fget_light +fs/file.c:746 +__fget_light +fs/file.c:750 +__fget_light +fs/file.c:760 +__fdget_pos +fs/file.c:784 +SyS_read +fs/read_write.c:562 +``` \ No newline at end of file diff --git a/docs/lmbench.md b/docs/lmbench.md new file mode 100644 index 00000000..29f568e7 --- /dev/null +++ b/docs/lmbench.md @@ -0,0 +1,37 @@ +# lmbench + + ____ _ ____ _____ + | _ \ | | / __ \ / ____| + | |_) |_ _| |_ ___| | | | (___ + | _ <| | | | __/ _ \ | | |\___ \ + | |_) | |_| | || __/ |__| |____) | + |____/ \__, |\__\___|\____/|_____/ + __/ | + |___/ + +latency measurements +Simple syscall: 7.2972 microseconds +Simple read: 8.8881 microseconds +Simple write: 8.2459 microseconds +Simple stat: 6005.5000 microseconds +Simple fstat: 8.9297 microseconds +Simple open/close: 6040.0000 microseconds +Select on 100 fd's: 16.6916 microseconds +Signal handler installation: 8.7532 microseconds +Signal handler overhead: 0.0179 microseconds +Pipe latency: 83.8587 microseconds +Process fork+exit: 2027.5000 microseconds +Process fork+execve: 2142.0000 microseconds +Process fork+/bin/sh -c: 6318.0000 microseconds +File /var/tmp/XXX write bandwidth:11377 KB/sec +0.524288 16585 +file system latency +0k 3 52 94 +1k 3 51 95 +4k 3 53 91 +10k 3 48 91 +Bandwidth measurements +0.524288 29.14 +0.524288 22.16 +0.524288 13393.47 +0.524288 19.53 diff --git "a/docs/modules\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/modules\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" new file mode 100644 index 00000000..2899d11e --- /dev/null +++ "b/docs/modules\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" @@ -0,0 +1,18 @@ +# modules部分文件结构 + +``` +├── devfs //devfs文件系统 +├── devices //设备相关功能 +├── executor //执行器 +├── frame_allocator //页帧分配器 +├── fs //文件系统 +├── hal //硬件抽象层 +├── kalloc //内存分配器 +├── kheader //内核头文件 +├── logging //日志功能 +├── procfs //procfs文件系统 +├── ramfs //RAM文件系统 +├── signal //信号处理 +└── sync //同步功能 +``` + diff --git a/docs/nbench.md b/docs/nbench.md new file mode 100644 index 00000000..8565941d --- /dev/null +++ b/docs/nbench.md @@ -0,0 +1,48 @@ +# nbench + +> 利用 nbench 进行性能测试 + +## ByteOS (qemu-system-riscv64) + ____ _ ____ _____ + | _ \ | | / __ \ / ____| + | |_) |_ _| |_ ___| | | | (___ + | _ <| | | | __/ _ \ | | |\___ \ + | |_) | |_| | || __/ |__| |____) | + |____/ \__, |\__\___|\____/|_____/ + __/ | + |___/ + + +BYTEmark* Native Mode Benchmark ver. 2 (10/95) +Index-split by Andrew D. Balsa (11/97) +Linux/Unix* port by Uwe F. Mayer (12/96,11/97) + +TEST : Iterations/sec. : Old Index : New Index + : : Pentium 90* : AMD K6/233* +--------------------:------------------:-------------:------------ +NUMERIC SORT : 879 : 22.54 : 7.40 +STRING SORT : 17.575 : 7.85 : 1.22 +BITFIELD : 4.2969e+08 : 73.71 : 15.40 +FP EMULATION : 175.84 : 84.38 : 19.47 +FOURIER : 8865.2 : 10.08 : 5.66 +ASSIGNMENT : 29.84 : 113.55 : 29.45 +IDEA : 4659.2 : 71.26 : 21.16 +HUFFMAN : 1886.4 : 52.31 : 16.70 + +## Linux (qemu-riscv64) + +BYTEmark* Native Mode Benchmark ver. 2 (10/95) +Index-split by Andrew D. Balsa (11/97) +Linux/Unix* port by Uwe F. Mayer (12/96,11/97) + +TEST : Iterations/sec. : Old Index : New Index + : : Pentium 90* : AMD K6/233* +--------------------:------------------:-------------:------------ +NUMERIC SORT : 1130.1 : 28.98 : 9.52 +STRING SORT : 36.48 : 16.30 : 2.52 +BITFIELD : 7.1698e+08 : 122.99 : 25.69 +FP EMULATION : 200.99 : 96.44 : 22.25 +FOURIER : 10046 : 11.43 : 6.42 +ASSIGNMENT : 36.577 : 139.18 : 36.10 +IDEA : 5445.9 : 83.29 : 24.73 +HUFFMAN : 2791 : 77.39 : 24.71 \ No newline at end of file diff --git a/docs/org.md b/docs/org.md new file mode 100644 index 00000000..e1c66f2e --- /dev/null +++ b/docs/org.md @@ -0,0 +1,22 @@ +# 想法 +在 https://github.com/byte-os 分几类 + +基础架构 +arch-riscv-qemu +arch-riscv-cv1811h +驱动 +driver-uart-dw-apb-uart +driver-eth-cvitek-ethernet +模块 +module-devfs +module-executor +module-frame-allocator +内核 +kernel-posix +kernel-rtos +kernel-zircon +kernel-sel4 +工具 +tools-kbuilder + +类似: kbuilder config \ No newline at end of file diff --git a/docs/procfs.md b/docs/procfs.md new file mode 100644 index 00000000..bfb11a35 --- /dev/null +++ b/docs/procfs.md @@ -0,0 +1,101 @@ +# procfs + +procfs(/proc文件系统)是一种特殊的虚拟文件系统,它提供了一种以文件和目录的形式访问内核信息的方式。它是在许多类Unix操作系统中实现的,包括Linux。 + +procfs不是一个真正的文件系统,它没有对应的磁盘上的存储空间。相反,它是通过在内核中创建一个虚拟文件系统接口,将内核数据和状态以文件的形式呈现给用户空间。这些文件和目录可以被用户和应用程序访问和读取,提供了一种交互式地查看和监控内核信息的方式。 + +在procfs中,每个进程都有一个对应的目录,目录的名称是进程的PID(进程标识符)。在每个进程目录下,可以找到与该进程相关的各种信息,如进程状态、命令行参数、内存映射、打开的文件等。此外,procfs还提供了一些特殊的文件和目录,用于访问系统级别的信息,如CPU信息、内存信息、系统状态等。 + +通过读取procfs中的文件,用户和应用程序可以获取有关系统和进程的详细信息,监测系统性能,诊断问题,并与内核交互。这种以文件和目录的形式公开内核信息的设计使得procfs非常灵活和易于使用。 + +## 主要设计 + +```rust +impl INodeInterface for DevDirContainer { + fn open(&self, name: &str, _flags: vfscore::OpenFlags) -> VfsResult> { + self.inner + .map + .get(name) + .map(|x| x.clone()) + .ok_or(VfsError::FileNotFound) + } + + fn read_dir(&self) -> VfsResult> { + Ok(self + .inner + .map + .iter() + .map(|(name, _)| DirEntry { + filename: name.to_string(), + len: 0, + file_type: FileType::Device, + }) + .collect()) + } + + fn stat(&self, stat: &mut vfscore::Stat) -> VfsResult<()> { + ... + Ok(()) + } + + fn metadata(&self) -> VfsResult { + Ok(vfscore::Metadata { + filename: "dev", + inode: 0, + file_type: FileType::Directory, + size: 0, + childrens: self.inner.map.len(), + }) + } + + fn getdents(&self, buffer: &mut [u8]) -> VfsResult { + let buf_ptr = buffer.as_mut_ptr() as usize; + let len = buffer.len(); + let mut ptr: usize = buf_ptr; + let mut finished = 0; + for (i, x) in self + .inner + .map + .iter() + .enumerate() + .skip(*self.dents_off.lock()) + { + let filename = x.0; + let file_bytes = filename.as_bytes(); + let current_len = size_of::() + file_bytes.len() + 1; + if len - (ptr - buf_ptr) < current_len { + break; + } + + // let dirent = c2rust_ref(ptr as *mut Dirent); + let dirent: &mut Dirent64 = unsafe { (ptr as *mut Dirent64).as_mut() }.unwrap(); + + dirent.ino = 0; + dirent.off = current_len as i64; + dirent.reclen = current_len as u16; + + dirent.ftype = 0; // 0 ftype is file + + let buffer = unsafe { + core::slice::from_raw_parts_mut(dirent.name.as_mut_ptr(), file_bytes.len() + 1) + }; + buffer[..file_bytes.len()].copy_from_slice(file_bytes); + buffer[file_bytes.len()] = b'\0'; + ptr = ptr + current_len; + finished = i + 1; + } + *self.dents_off.lock() = finished; + Ok(ptr - buf_ptr) + } +} +``` + +在`INodeInterface`的实现中,`open`函数用于打开一个文件或子目录,根据给定的名称在`inner.map`中查找相应的目录项,并返回对应的`INodeInterface`实例。如果找不到对应的目录项,则返回`FileNotFound`错误。 + +`read_dir`函数用于读取目录的内容,返回一个包含目录项信息的`Vec`。在这个例子中,通过遍历`inner.map`中的目录项,为每个目录项创建一个`DirEntry`,并将其加入到结果`Vec`中。这里的目录项类型被指定为`FileType::Device`,长度为0。 + +`stat`函数用于获取文件或目录的元数据(stat信息),接受一个`Stat`结构体的引用,并在该结构体中填充相应的字段。在这个例子中,为了表示这是一个目录,`mode`字段被设置为`StatMode::DIR`,其他字段被赋予了一些默认值,与之前的代码段中的`MemInfo`和`Mounts`结构体的`stat`函数实现相同。 + +`metadata`函数用于获取文件或目录的元数据,返回一个`vfscore::Metadata`结构体,其中包含文件名、节点号、文件类型、大小和子目录项数量等信息。在这个例子中,文件名为"dev",节点号为0,文件类型为`FileType::Directory`,大小为0,子目录项的数量为`inner.map`的长度。 + +`getdents`函数用于读取目录的目录项(dentry)。它接受一个缓冲区`buffer`,并将目录项的信息填充到缓冲区中。函数内部使用了`Dirent64`结构体表示目录项的格式。通过遍历`inner.map`中的目录项,将每个目录项的信息填充到缓冲区中,并更新指针`ptr`和偏移`finished`。最后,将更新后的偏移存储在`self.dents_off`中,并返回填充到缓冲区中的字节数。 diff --git a/docs/questions.md b/docs/questions.md new file mode 100644 index 00000000..aff980fc --- /dev/null +++ b/docs/questions.md @@ -0,0 +1,7 @@ +# questions + +> 前面的忘记记录了,想起来之后再次记录。 + +## 2023/4/20 PageFault 的问题, + +由于想要实现 `COW`, 所以对栈进行了复制,但是存在问题,如果主线程先执行,主线程会回到函数里,然后改变栈的内容,导致 `fork` 的无法正常执行,所以 `COW` 机制应该跳过栈的内容。 \ No newline at end of file diff --git a/docs/ramfs.md b/docs/ramfs.md new file mode 100644 index 00000000..6a443894 --- /dev/null +++ b/docs/ramfs.md @@ -0,0 +1,537 @@ +# ramfs + +Ramfs(RAM文件系统)是一种特殊类型的文件系统,它将文件和目录存储在计算机的内存中而不是磁盘上。它是一种基于内存的虚拟文件系统,允许在内存中创建文件和目录,并进行读取、写入和访问操作。 + +以下是Ramfs的一些关键特点和优势: + +1. **速度和性能**:由于文件和目录存储在内存中,Ramfs能够提供非常快速的读取和写入操作。由于内存的访问速度远远超过磁盘访问速度,Ramfs在处理大量小型文件或需要高性能读写的应用程序方面表现出色。 +2. **易于使用和实现**:Ramfs非常简单,易于实现和使用。它不涉及磁盘I/O操作,也不需要复杂的文件系统结构。这使得它成为实现临时文件系统、缓存文件系统或用于特定用途的文件系统的理想选择。 +3. **临时性质**:由于Ramfs是基于内存的,它通常用于存储临时文件或运行时数据。一旦系统关闭或重新启动,Ramfs中的数据将丢失。这使得Ramfs特别适用于需要快速访问和临时存储的数据,而不需要长期保留。 +4. **低存储容量要求**:相比于磁盘文件系统,Ramfs对存储容量的要求较低。它不需要预留大量的磁盘空间,而是根据需要动态分配内存。这使得Ramfs在资源受限的环境中尤为有用,如嵌入式系统或嵌入式设备。 +5. **易于清除和重置**:由于Ramfs中的数据在系统重启时会被清除,它非常适合进行系统重置或恢复操作。通过重新启动系统,Ramfs可以快速恢复到初始状态,不会留下残留的文件或数据。 + +需要注意的是,由于Ramfs存储在内存中,它的容量受限于系统的可用内存。在使用Ramfs时,应仔细考虑可用内存的大小和系统的需求,以避免内存不足或系统性能下降的问题。 + +## 主要实现 + +```rust +pub struct RamFs { + root: Arc, +} + +impl RamFs { + pub fn new() -> Arc { + let inner = Arc::new(RamDirInner { + name: String::from(""), + children: Mutex::new(Vec::new()), + }); + Arc::new(Self { root: inner }) + } +} + +impl FileSystem for RamFs { + fn root_dir(&'static self) -> Arc { + Arc::new(RamDir { + inner: self.root.clone(), + dents_off: Mutex::new(0), + }) + } + + fn name(&self) -> &str { + "ramfs" + } +} + +pub struct RamDirInner { + name: String, + children: Mutex>, +} + +// TODO: use frame insteads of Vec. +pub struct RamFileInner { + name: String, + // content: Mutex>, + len: Mutex, + pages: Mutex>, + times: Mutex<[TimeSpec; 3]>, // ctime, atime, mtime. +} + +#[allow(dead_code)] +pub struct RamLinkInner { + name: String, + link_file: Arc, +} + +pub enum FileContainer { + File(Arc), + Dir(Arc), + Link(Arc), +} + +impl FileContainer { + #[inline] + fn to_inode(&self) -> VfsResult> { + match self { + FileContainer::File(file) => Ok(Arc::new(RamFile { + inner: file.clone(), + })), + FileContainer::Dir(dir) => Ok(Arc::new(RamDir { + inner: dir.clone(), + dents_off: Mutex::new(0), + })), + FileContainer::Link(link) => Ok(Arc::new(RamLink { + inner: link.clone(), + link_file: link.link_file.clone(), + })), + } + } + + #[inline] + fn filename(&self) -> &str { + match self { + FileContainer::File(file) => &file.name, + FileContainer::Dir(dir) => &dir.name, + FileContainer::Link(link) => &link.name, + } + } +} +``` + +- `RamFs`结构体:代表整个RAM文件系统。它包含一个指向根目录的`Arc`。 +- `impl RamFs`:为RamFs实现了一些方法。 + - `new()`方法:用于创建一个新的RamFs实例。它初始化了一个`RamDirInner`结构体作为根目录,并将其封装在`Arc`中返回。 + - `root_dir()`方法:返回根目录的`Arc`实例,这是文件系统接口的一部分。 + - `name()`方法:返回文件系统的名称,即"ramfs"。 +- `RamDirInner`结构体:表示RAM文件系统中的目录。它包含目录的名称和子项的列表。子项列表通过互斥锁`Mutex`来实现并发安全。 +- `RamFileInner`结构体:表示RAM文件系统中的文件。它包含文件的名称、长度、页列表和时间戳。文件长度和页列表都被互斥锁`Mutex`保护。 +- `RamLinkInner`结构体:表示RAM文件系统中的链接(符号链接)。它包含链接的名称和指向的文件(通过`Arc`表示)。 +- `FileContainer`枚举:表示文件系统中的文件、目录和链接。它可以是`File`(文件)、`Dir`(目录)或`Link`(链接)。每个变体包含对应类型的内部结构体的`Arc`。 +- `impl FileContainer`:为`FileContainer`实现了一些方法。 + - `to_inode()`方法:将`FileContainer`转换为`Arc`实例。根据`FileContainer`的类型,返回对应的`RamFile`、`RamDir`或`RamLink`实例。 + - `filename()`方法:返回`FileContainer`的文件名。 + +```rust +#[allow(dead_code)] +pub struct RamLink { + inner: Arc, + link_file: Arc, +} + +pub struct RamDir { + inner: Arc, + dents_off: Mutex, +} + +impl INodeInterface for RamDir { + fn open(&self, name: &str, _flags: vfscore::OpenFlags) -> VfsResult> { + self.inner + .children + .lock() + .iter() + .find(|x| x.filename() == name) + .map(|x| x.to_inode()) + .ok_or(VfsError::FileNotFound)? + } + + fn touch(&self, name: &str) -> VfsResult> { + // Find file, return VfsError::AlreadyExists if file exists + self.inner + .children + .lock() + .iter() + .find(|x| x.filename() == name) + .map_or(Ok(()), |_| Err(VfsError::AlreadyExists))?; + + let new_inner = Arc::new(RamFileInner { + name: String::from(name), + // content: Mutex::new(Vec::new()), + times: Mutex::new([Default::default(); 3]), + len: Mutex::new(0), + pages: Mutex::new(vec![]), + }); + + let new_file = Arc::new(RamFile { + inner: new_inner.clone(), + }); + + self.inner + .children + .lock() + .push(FileContainer::File(new_inner)); + + Ok(new_file) + } + + fn mkdir(&self, name: &str) -> VfsResult> { + // Find file, return VfsError::AlreadyExists if file exists + self.inner + .children + .lock() + .iter() + .find(|x| x.filename() == name) + .map_or(Ok(()), |_| Err(VfsError::AlreadyExists))?; + + let new_inner = Arc::new(RamDirInner { + name: String::from(name), + children: Mutex::new(Vec::new()), + }); + + let new_dir = Arc::new(RamDir { + inner: new_inner.clone(), + dents_off: Mutex::new(0), + }); + + self.inner + .children + .lock() + .push(FileContainer::Dir(new_inner)); + + Ok(new_dir) + } + + fn rmdir(&self, name: &str) -> VfsResult<()> { + // TODO: identify whether the dir is empty(through metadata.childrens) + // return DirectoryNotEmpty if not empty. + let len = self + .inner + .children + .lock() + .drain_filter(|x| match x { + FileContainer::Dir(x) => x.name == name, + _ => false, + }) + .count(); + match len > 0 { + true => Ok(()), + false => Err(VfsError::FileNotFound), + } + } + + fn read_dir(&self) -> VfsResult> { + Ok(self + .inner + .children + .lock() + .iter() + .map(|x| match x { + FileContainer::File(file) => DirEntry { + filename: file.name.clone(), + // len: file.content.lock().len(), + len: *file.len.lock(), + file_type: FileType::File, + }, + FileContainer::Dir(dir) => DirEntry { + filename: dir.name.clone(), + len: 0, + file_type: FileType::Directory, + }, + FileContainer::Link(link) => DirEntry { + filename: link.name.clone(), + len: 0, + file_type: FileType::Link, + }, + }) + .collect()) + } + + fn remove(&self, name: &str) -> VfsResult<()> { + let len = self + .inner + .children + .lock() + .drain_filter(|x| match x { + FileContainer::File(x) => x.name == name, + FileContainer::Dir(_) => false, + FileContainer::Link(x) => x.name == name, + }) + .count(); + match len > 0 { + true => Ok(()), + false => Err(VfsError::FileNotFound), + } + } + + fn unlink(&self, name: &str) -> VfsResult<()> { + self.remove(name) + } + + fn metadata(&self) -> VfsResult { + Ok(Metadata { + filename: &self.inner.name, + inode: 0, + file_type: FileType::Directory, + size: 0, + childrens: self.inner.children.lock().len(), + }) + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + stat.ino = 1; // TODO: convert path to number(ino) + stat.mode = StatMode::DIR; // TODO: add access mode + stat.nlink = 1; + stat.uid = 0; + stat.gid = 0; + stat.size = 0; + stat.blksize = 512; + stat.blocks = 0; + stat.rdev = 0; // TODO: add device id + stat.mtime = Default::default(); + stat.atime = Default::default(); + stat.ctime = Default::default(); + Ok(()) + } + + fn getdents(&self, buffer: &mut [u8]) -> VfsResult { + let buf_ptr = buffer.as_mut_ptr() as usize; + let len = buffer.len(); + let mut ptr: usize = buf_ptr; + let mut finished = 0; + for (i, x) in self + .inner + .children + .lock() + .iter() + .enumerate() + .skip(*self.dents_off.lock()) + { + let filename = x.filename(); + let file_bytes = filename.as_bytes(); + let current_len = size_of::() + file_bytes.len() + 1; + if len - (ptr - buf_ptr) < current_len { + break; + } + + // let dirent = c2rust_ref(ptr as *mut Dirent); + let dirent: &mut Dirent64 = unsafe { (ptr as *mut Dirent64).as_mut() }.unwrap(); + + dirent.ino = 0; + dirent.off = current_len as i64; + dirent.reclen = current_len as u16; + + dirent.ftype = 0; // 0 ftype is file + + let buffer = unsafe { + core::slice::from_raw_parts_mut(dirent.name.as_mut_ptr(), file_bytes.len() + 1) + }; + buffer[..file_bytes.len()].copy_from_slice(file_bytes); + buffer[file_bytes.len()] = b'\0'; + ptr = ptr + current_len; + finished = i + 1; + } + *self.dents_off.lock() = finished; + Ok(ptr - buf_ptr) + } + + fn link(&self, name: &str, src: Arc) -> VfsResult<()> { + // Find file, return VfsError::AlreadyExists if file exists + self.inner + .children + .lock() + .iter() + .find(|x| x.filename() == name) + .map_or(Ok(()), |_| Err(VfsError::AlreadyExists))?; + + let new_inner = Arc::new(RamLinkInner { + name: String::from(name), + link_file: src, + }); + + self.inner + .children + .lock() + .push(FileContainer::Link(new_inner)); + + Ok(()) + } +} +``` + +这部分代码实现了`RamDir`结构体,它表示RAM文件系统中的目录。`RamDir`实现了`INodeInterface` trait,该trait定义了文件系统操作的接口方法。 + +以下是代码的解释: + +- `RamLink`结构体:表示RAM文件系统中的链接。它包含一个指向`RamLinkInner`的`Arc`和一个指向链接的文件的`Arc`。 +- `RamDir`结构体:表示RAM文件系统中的目录。它包含一个指向`RamDirInner`的`Arc`和一个用于追踪目录项偏移量的`Mutex`。 +- `impl INodeInterface for RamDir`:为`RamDir`实现了`INodeInterface` trait中的方法。 + - `open()`方法:根据给定的名称查找目录中的子项,并返回对应的`Arc`实例。如果找不到子项,则返回`VfsError::FileNotFound`错误。 + - `touch()`方法:创建一个新文件,并将其添加到目录中。如果目录中已存在同名的文件,则返回`VfsError::AlreadyExists`错误。 + - `mkdir()`方法:创建一个新目录,并将其添加到目录中。如果目录中已存在同名的目录,则返回`VfsError::AlreadyExists`错误。 + - `rmdir()`方法:删除指定的目录。如果目录不为空,则返回`VfsError::DirectoryNotEmpty`错误。 + - `read_dir()`方法:返回目录中的所有目录项的列表。每个目录项都包含文件名、长度和文件类型。 + - `remove()`方法:从目录中移除指定的目录项(文件、目录或链接)。 + - `unlink()`方法:从目录中移除指定的链接。 + - `metadata()`方法:返回目录的元数据,包括文件名、inode、文件类型、大小和子项数量。 + - `stat()`方法:填充`Stat`结构体,包含目录的状态信息,如inode号、访问模式、链接数等。 + - `getdents()`方法:将目录中的目录项填充到提供的缓冲区中。 + - `link()`方法:在目录中创建一个链接,将其指向另一个文件。 + +这部分代码扩展了RAM文件系统的功能,实现了目录的创建、删除、查找等操作,并提供了与目录相关的元数据和状态信息。 + +```rust +pub struct RamFile { + inner: Arc, +} + +impl INodeInterface for RamFile { + fn readat(&self, mut offset: usize, buffer: &mut [u8]) -> VfsResult { + let mut buffer_off = 0; + // let file_size = self.inner.content.lock().len(); + let file_size = *self.inner.len.lock(); + let inner = self.inner.pages.lock(); + + match offset >= file_size { + true => Ok(0), + false => { + // let origin_read_len = min(buffer.len(), file_size - offset); + // let read_len = if offset >= real_size { + // min(origin_read_len, real_size - offset) + // } else { + // 0 + // }; + let read_len = min(buffer.len(), file_size - offset); + let mut last_len = read_len; + // let content = self.inner.content.lock(); + // buffer[..read_len].copy_from_slice(&content[offset..(offset + read_len)]); + loop { + let curr_size = cmp::min(PAGE_SIZE - offset % PAGE_SIZE, last_len); + if curr_size == 0 { + break; + } + let index = offset / PAGE_SIZE; + let page_data = inner[index].0.get_buffer(); + buffer[buffer_off..buffer_off + curr_size].copy_from_slice( + &page_data[offset % PAGE_SIZE..offset % PAGE_SIZE + curr_size], + ); + offset += curr_size; + last_len -= curr_size; + buffer_off += curr_size; + } + // Ok(origin_read_len) + Ok(read_len) + } + } + } + + fn writeat(&self, mut offset: usize, buffer: &[u8]) -> VfsResult { + let mut buffer_off = 0; + let pages = ceil_div(offset + buffer.len(), PAGE_SIZE); + + let mut inner = self.inner.pages.lock(); + + for _ in inner.len()..pages { + inner.push(frame_alloc().expect("can't alloc frame in ram fs")); + } + + let mut wsize = buffer.len(); + loop { + let curr_size = cmp::min(PAGE_SIZE - offset % PAGE_SIZE, wsize); + if curr_size == 0 { + break; + } + let index = offset / PAGE_SIZE; + let page_data = inner[index].0.get_buffer(); + page_data[offset % PAGE_SIZE..offset % PAGE_SIZE + curr_size] + .copy_from_slice(&buffer[buffer_off..buffer_off + curr_size]); + offset += curr_size; + buffer_off += curr_size; + wsize -= curr_size; + } + + let file_size = *self.inner.len.lock(); + if offset > file_size { + *self.inner.len.lock() = offset; + } + Ok(buffer.len()) + } + + fn truncate(&self, size: usize) -> VfsResult<()> { + // self.inner.content.lock().drain(size..); + *self.inner.len.lock() = size; + + let mut page_cont = self.inner.pages.lock(); + let pages = page_cont.len(); + let target_pages = ceil_div(size, PAGE_SIZE); + + for _ in pages..target_pages { + page_cont.push(frame_alloc().expect("can't alloc frame in ram fs")); + } + + Ok(()) + } + + fn metadata(&self) -> VfsResult { + Ok(Metadata { + filename: &self.inner.name, + inode: 0, + file_type: FileType::File, + // size: self.inner.content.lock().len(), + size: *self.inner.len.lock(), + childrens: 0, + }) + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + // stat.ino = 1; // TODO: convert path to number(ino) + if self.inner.name.ends_with(".s") { + stat.ino = 2; // TODO: convert path to number(ino) + } else { + stat.ino = 1; // TODO: convert path to number(ino) + } + stat.mode = StatMode::FILE; // TODO: add access mode + stat.nlink = 1; + stat.uid = 0; + stat.gid = 0; + // stat.size = self.inner.content.lock().len() as u64; + stat.size = *self.inner.len.lock() as u64; + stat.blksize = 512; + stat.blocks = 0; + stat.rdev = 0; // TODO: add device id + + stat.atime = self.inner.times.lock()[1]; + stat.mtime = self.inner.times.lock()[2]; + Ok(()) + } + + fn utimes(&self, times: &mut [vfscore::TimeSpec]) -> VfsResult<()> { + if times[0].nsec != UTIME_OMIT { + self.inner.times.lock()[1] = times[0]; + } + if times[1].nsec != UTIME_OMIT { + self.inner.times.lock()[2] = times[1]; + } + Ok(()) + } +} + +impl INodeInterface for RamLink { + fn metadata(&self) -> VfsResult { + self.link_file.metadata() + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + self.link_file.stat(stat) + } + + fn readat(&self, offset: usize, buffer: &mut [u8]) -> VfsResult { + self.link_file.readat(offset, buffer) + } +} +``` + +这部分代码实现了`RamFile`和`RamLink`结构体,它们分别表示RAM文件系统中的文件和链接。这些结构体都实现了`INodeInterface` trait,该trait定义了文件系统操作的接口方法。 + +以下是代码的解释: + +- `RamFile`结构体:表示RAM文件系统中的文件。它包含一个指向`RamFileInner`的`Arc`。 +- `impl INodeInterface for RamFile`:为`RamFile`实现了`INodeInterface` trait中的方法。 + - `readat()`方法:从文件中读取数据到提供的缓冲区。根据指定的偏移量和缓冲区的大小,将文件中的数据复制到缓冲区中。 + - `writeat()`方法:将提供的数据写入文件的指定偏移量处。如果需要,会动态分配足够的内存页来容纳写入的数据。 + - `truncate()`方法:将文件截断到指定大小。如果指定的大小小于文件的当前大小,则会删除多余的数据页。如果指定的大小大于文件的当前大小,则会动态分配足够的内存页来扩展文件。 + - `metadata()`方法:返回文件的元数据,包括文件名、inode、文件类型、大小和子项数量。 + - `stat()`方法:填充`Stat`结构体,包含文件的状态信息,如inode号、访问模式、链接数等。 + - `utimes()`方法:更新文件的访问时间和修改时间。 +- `RamLink`结构体:表示RAM文件系统中的链接。它包含一个指向其他文件的`Arc`。 +- `impl INodeInterface for RamLink`:为`RamLink`实现了`INodeInterface` trait中的方法。 + - `metadata()`方法:返回链接的元数据,即链接指向的文件的元数据。 + - `stat()`方法:填充`Stat`结构体,包含链接指向的文件的状态信息。 + - `readat()`方法:从链接指向的文件中读取数据。 diff --git a/docs/riscv-syscall.h.in b/docs/riscv-syscall.h.in new file mode 100644 index 00000000..3805dcaf --- /dev/null +++ b/docs/riscv-syscall.h.in @@ -0,0 +1,304 @@ +#define __NR_io_setup 0 +#define __NR_io_destroy 1 +#define __NR_io_submit 2 +#define __NR_io_cancel 3 +#define __NR_io_getevents 4 +#define __NR_setxattr 5 +#define __NR_lsetxattr 6 +#define __NR_fsetxattr 7 +#define __NR_getxattr 8 +#define __NR_lgetxattr 9 +#define __NR_fgetxattr 10 +#define __NR_listxattr 11 +#define __NR_llistxattr 12 +#define __NR_flistxattr 13 +#define __NR_removexattr 14 +#define __NR_lremovexattr 15 +#define __NR_fremovexattr 16 +#define __NR_getcwd 17 +#define __NR_lookup_dcookie 18 +#define __NR_eventfd2 19 +#define __NR_epoll_create1 20 +#define __NR_epoll_ctl 21 +#define __NR_epoll_pwait 22 +#define __NR_dup 23 +#define __NR_dup3 24 +#define __NR_fcntl 25 +#define __NR_inotify_init1 26 +#define __NR_inotify_add_watch 27 +#define __NR_inotify_rm_watch 28 +#define __NR_ioctl 29 +#define __NR_ioprio_set 30 +#define __NR_ioprio_get 31 +#define __NR_flock 32 +#define __NR_mknodat 33 +#define __NR_mkdirat 34 +#define __NR_unlinkat 35 +#define __NR_symlinkat 36 +#define __NR_linkat 37 +#define __NR_umount2 39 +#define __NR_mount 40 +#define __NR_pivot_root 41 +#define __NR_nfsservctl 42 +#define __NR_statfs 43 +#define __NR_fstatfs 44 +#define __NR_truncate 45 +#define __NR_ftruncate 46 +#define __NR_fallocate 47 +#define __NR_faccessat 48 +#define __NR_chdir 49 +#define __NR_fchdir 50 +#define __NR_chroot 51 +#define __NR_fchmod 52 +#define __NR_fchmodat 53 +#define __NR_fchownat 54 +#define __NR_fchown 55 +#define __NR_openat 56 +#define __NR_close 57 +#define __NR_vhangup 58 +#define __NR_pipe2 59 +#define __NR_quotactl 60 +#define __NR_getdents64 61 +#define __NR_lseek 62 +#define __NR_read 63 +#define __NR_write 64 +#define __NR_readv 65 +#define __NR_writev 66 +#define __NR_pread64 67 +#define __NR_pwrite64 68 +#define __NR_preadv 69 +#define __NR_pwritev 70 +#define __NR_sendfile 71 +#define __NR_pselect6 72 +#define __NR_ppoll 73 +#define __NR_signalfd4 74 +#define __NR_vmsplice 75 +#define __NR_splice 76 +#define __NR_tee 77 +#define __NR_readlinkat 78 +#define __NR_newfstatat 79 +#define __NR_fstat 80 +#define __NR_sync 81 +#define __NR_fsync 82 +#define __NR_fdatasync 83 +#define __NR_sync_file_range 84 +#define __NR_timerfd_create 85 +#define __NR_timerfd_settime 86 +#define __NR_timerfd_gettime 87 +#define __NR_utimensat 88 +#define __NR_acct 89 +#define __NR_capget 90 +#define __NR_capset 91 +#define __NR_personality 92 +#define __NR_exit 93 +#define __NR_exit_group 94 +#define __NR_waitid 95 +#define __NR_set_tid_address 96 +#define __NR_unshare 97 +#define __NR_futex 98 +#define __NR_set_robust_list 99 +#define __NR_get_robust_list 100 +#define __NR_nanosleep 101 +#define __NR_getitimer 102 +#define __NR_setitimer 103 +#define __NR_kexec_load 104 +#define __NR_init_module 105 +#define __NR_delete_module 106 +#define __NR_timer_create 107 +#define __NR_timer_gettime 108 +#define __NR_timer_getoverrun 109 +#define __NR_timer_settime 110 +#define __NR_timer_delete 111 +#define __NR_clock_settime 112 +#define __NR_clock_gettime 113 +#define __NR_clock_getres 114 +#define __NR_clock_nanosleep 115 +#define __NR_syslog 116 +#define __NR_ptrace 117 +#define __NR_sched_setparam 118 +#define __NR_sched_setscheduler 119 +#define __NR_sched_getscheduler 120 +#define __NR_sched_getparam 121 +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#define __NR_sched_yield 124 +#define __NR_sched_get_priority_max 125 +#define __NR_sched_get_priority_min 126 +#define __NR_sched_rr_get_interval 127 +#define __NR_restart_syscall 128 +#define __NR_kill 129 +#define __NR_tkill 130 +#define __NR_tgkill 131 +#define __NR_sigaltstack 132 +#define __NR_rt_sigsuspend 133 +#define __NR_rt_sigaction 134 +#define __NR_rt_sigprocmask 135 +#define __NR_rt_sigpending 136 +#define __NR_rt_sigtimedwait 137 +#define __NR_rt_sigqueueinfo 138 +#define __NR_rt_sigreturn 139 +#define __NR_setpriority 140 +#define __NR_getpriority 141 +#define __NR_reboot 142 +#define __NR_setregid 143 +#define __NR_setgid 144 +#define __NR_setreuid 145 +#define __NR_setuid 146 +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#define __NR_setfsuid 151 +#define __NR_setfsgid 152 +#define __NR_times 153 +#define __NR_setpgid 154 +#define __NR_getpgid 155 +#define __NR_getsid 156 +#define __NR_setsid 157 +#define __NR_getgroups 158 +#define __NR_setgroups 159 +#define __NR_uname 160 +#define __NR_sethostname 161 +#define __NR_setdomainname 162 +#define __NR_getrlimit 163 +#define __NR_setrlimit 164 +#define __NR_getrusage 165 +#define __NR_umask 166 +#define __NR_prctl 167 +#define __NR_getcpu 168 +#define __NR_gettimeofday 169 +#define __NR_settimeofday 170 +#define __NR_adjtimex 171 +#define __NR_getpid 172 +#define __NR_getppid 173 +#define __NR_getuid 174 +#define __NR_geteuid 175 +#define __NR_getgid 176 +#define __NR_getegid 177 +#define __NR_gettid 178 +#define __NR_sysinfo 179 +#define __NR_mq_open 180 +#define __NR_mq_unlink 181 +#define __NR_mq_timedsend 182 +#define __NR_mq_timedreceive 183 +#define __NR_mq_notify 184 +#define __NR_mq_getsetattr 185 +#define __NR_msgget 186 +#define __NR_msgctl 187 +#define __NR_msgrcv 188 +#define __NR_msgsnd 189 +#define __NR_semget 190 +#define __NR_semctl 191 +#define __NR_semtimedop 192 +#define __NR_semop 193 +#define __NR_shmget 194 +#define __NR_shmctl 195 +#define __NR_shmat 196 +#define __NR_shmdt 197 +#define __NR_socket 198 +#define __NR_socketpair 199 +#define __NR_bind 200 +#define __NR_listen 201 +#define __NR_accept 202 +#define __NR_connect 203 +#define __NR_getsockname 204 +#define __NR_getpeername 205 +#define __NR_sendto 206 +#define __NR_recvfrom 207 +#define __NR_setsockopt 208 +#define __NR_getsockopt 209 +#define __NR_shutdown 210 +#define __NR_sendmsg 211 +#define __NR_recvmsg 212 +#define __NR_readahead 213 +#define __NR_brk 214 +#define __NR_munmap 215 +#define __NR_mremap 216 +#define __NR_add_key 217 +#define __NR_request_key 218 +#define __NR_keyctl 219 +#define __NR_clone 220 +#define __NR_execve 221 +#define __NR_mmap 222 +#define __NR_fadvise64 223 +#define __NR_swapon 224 +#define __NR_swapoff 225 +#define __NR_mprotect 226 +#define __NR_msync 227 +#define __NR_mlock 228 +#define __NR_munlock 229 +#define __NR_mlockall 230 +#define __NR_munlockall 231 +#define __NR_mincore 232 +#define __NR_madvise 233 +#define __NR_remap_file_pages 234 +#define __NR_mbind 235 +#define __NR_get_mempolicy 236 +#define __NR_set_mempolicy 237 +#define __NR_migrate_pages 238 +#define __NR_move_pages 239 +#define __NR_rt_tgsigqueueinfo 240 +#define __NR_perf_event_open 241 +#define __NR_accept4 242 +#define __NR_recvmmsg 243 +#define __NR_arch_specific_syscall 244 +#define __NR_wait4 260 +#define __NR_prlimit64 261 +#define __NR_fanotify_init 262 +#define __NR_fanotify_mark 263 +#define __NR_name_to_handle_at 264 +#define __NR_open_by_handle_at 265 +#define __NR_clock_adjtime 266 +#define __NR_syncfs 267 +#define __NR_setns 268 +#define __NR_sendmmsg 269 +#define __NR_process_vm_readv 270 +#define __NR_process_vm_writev 271 +#define __NR_kcmp 272 +#define __NR_finit_module 273 +#define __NR_sched_setattr 274 +#define __NR_sched_getattr 275 +#define __NR_renameat2 276 +#define __NR_seccomp 277 +#define __NR_getrandom 278 +#define __NR_memfd_create 279 +#define __NR_bpf 280 +#define __NR_execveat 281 +#define __NR_userfaultfd 282 +#define __NR_membarrier 283 +#define __NR_mlock2 284 +#define __NR_copy_file_range 285 +#define __NR_preadv2 286 +#define __NR_pwritev2 287 +#define __NR_pkey_mprotect 288 +#define __NR_pkey_alloc 289 +#define __NR_pkey_free 290 +#define __NR_statx 291 +#define __NR_io_pgetevents 292 +#define __NR_rseq 293 +#define __NR_kexec_file_load 294 +#define __NR_pidfd_send_signal 424 +#define __NR_io_uring_setup 425 +#define __NR_io_uring_enter 426 +#define __NR_io_uring_register 427 +#define __NR_open_tree 428 +#define __NR_move_mount 429 +#define __NR_fsopen 430 +#define __NR_fsconfig 431 +#define __NR_fsmount 432 +#define __NR_fspick 433 +#define __NR_pidfd_open 434 +#define __NR_clone3 435 +#define __NR_close_range 436 +#define __NR_openat2 437 +#define __NR_pidfd_getfd 438 +#define __NR_faccessat2 439 +#define __NR_process_madvise 440 +#define __NR_epoll_pwait2 441 +#define __NR_mount_setattr 442 +#define __NR_landlock_create_ruleset 444 +#define __NR_landlock_add_rule 445 +#define __NR_landlock_restrict_self 446 + +#define __NR_sysriscv __NR_arch_specific_syscall +#define __NR_riscv_flush_icache (__NR_sysriscv + 15) \ No newline at end of file diff --git a/docs/step1-progress.md b/docs/step1-progress.md new file mode 100644 index 00000000..6c792639 --- /dev/null +++ b/docs/step1-progress.md @@ -0,0 +1,32 @@ +# Step1-progress + +- [x] brk +- [x] chdir +- [x] clone +- [x] close +- [x] dup +- [x] dup2 +- [x] execve +- [x] exit +- [x] fork +- [x] fstat +- [x] getcwd +- [x] getpid +- [x] getppid +- [x] gettimeofday +- [x] mkdir_ +- [x] mmap +- [x] mount +- [x] munmap +- [x] open +- [x] openat +- [x] pipe +- [x] read +- [x] sleep +- [x] umount +- [x] uname +- [x] unlink +- [x] wait +- [x] waitpid +- [x] write +- [x] yield diff --git a/docs/vfs.md b/docs/vfs.md new file mode 100644 index 00000000..c15a0062 --- /dev/null +++ b/docs/vfs.md @@ -0,0 +1,14 @@ +# vfs + +## mount + +早期我们使用 在 mount point 创建一个 .mount file 存储信息 + +This is a temporary method for supporting mount + +1. create a new dir as mount point +2. touch a .mount file with the target path at the folder + +use open to open mount point + +## diff --git "a/docs/\345\206\205\345\255\230\345\210\206\351\205\215\345\231\250.md" "b/docs/\345\206\205\345\255\230\345\210\206\351\205\215\345\231\250.md" new file mode 100644 index 00000000..eb3d7739 --- /dev/null +++ "b/docs/\345\206\205\345\255\230\345\210\206\351\205\215\345\231\250.md" @@ -0,0 +1,51 @@ +# 内存分配器 + +**ByteOS**的内存分配器较为简单,其实现如下: + +```rust +#![no_std] + +extern crate alloc; + +use buddy_system_allocator::LockedHeap; +use log::info; + +// 堆大小 +const HEAP_SIZE: usize = 0x0100_0000; + +// 堆空间 +#[link_section = ".bss.heap"] +static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; + +/// 堆内存分配器 +#[global_allocator] +static HEAP_ALLOCATOR: LockedHeap<30> = LockedHeap::empty(); + +/// 初始化堆内存分配器 +pub fn init() { + unsafe { + info!( + "kernel HEAP init: {:#x}-{:#x}", + HEAP.as_ptr() as usize, + HEAP.as_ptr() as usize + HEAP_SIZE + ); + HEAP_ALLOCATOR + .lock() + .init(HEAP.as_mut_ptr() as usize, HEAP_SIZE); + } +} +``` + +这段代码实现了一个基于伙伴系统的堆内存分配器。下面是对代码的简要介绍: + +- `buddy_system_allocator` 是一个用于实现伙伴系统内存分配的库。 +- `HEAP_SIZE` 常量定义了堆的大小。 +- `HEAP` 是一个静态数组,用于存储堆空间。 +- `HEAP_ALLOCATOR` 是一个 `LockedHeap` 类型的全局静态变量,用于表示堆内存分配器。 +- `init()` 函数用于初始化堆内存分配器。通过调用 `HEAP_ALLOCATOR` 的 `init()` 方法,将堆空间的起始地址和大小传递给堆内存分配器。 + +该堆内存分配器使用了伙伴系统的算法来管理内存分配和释放。它将堆空间划分为不同大小的内存块,并通过合并和分割操作来高效地分配和回收内存。通过定义全局的堆内存分配器,其他模块可以使用该分配器来进行动态内存分配。 + + + + diff --git "a/docs/\345\206\205\346\240\270\345\215\212\351\253\230\346\240\270.md" "b/docs/\345\206\205\346\240\270\345\215\212\351\253\230\346\240\270.md" new file mode 100644 index 00000000..8c2f55d9 --- /dev/null +++ "b/docs/\345\206\205\346\240\270\345\215\212\351\253\230\346\240\270.md" @@ -0,0 +1,211 @@ +# 内核半高核 + +> 参考资料: +> +> https://github.com/rcore-os/rCore/blob/master/kernel/src/arch/riscv/boot/entry64.asm +> +> https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials + +首先尝试从 `rCore` 中获得的代码: + +```assembly + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80200000 + # sp == 0x800xxxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 14 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 2. enable paging + # satp = (8 << 60) | PPN(boot_page_table_sv39) + lui t0, %hi(boot_page_table_sv39) + li t1, 0xffffffffc0000000 - 0x80000000 + sub t0, t0, t1 + srli t0, t0, 12 + li t1, 8 << 60 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + + # 3. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 4 * 8 + .global bootstacktop +bootstacktop: + + .section .data + .align 12 # page align +boot_page_table_sv39: + # 0x00000000_80000000 -> 0x80000000 (1G) + # 0xffffffff_c0000000 -> 0x80000000 (1G) + .quad 0 + .quad 0 + .quad (0x80000 << 10) | 0xcf # VRWXAD + .zero 8 * 508 + .quad (0x80000 << 10) | 0xcf # VRWXAD +``` + +linker.ld + +```ld +/* 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 = 0xffffffffc0200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + _copy_user_start = .; + *(.text.copy_user) + _copy_user_end = .; + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + ebss = .; + } + + PROVIDE(end = .); +} +``` + +但是放在内核中,并没有启动起来,由于使用是 `qemu` 提供的 `opensbi`,能够检测地址然后直接跳过去,所以跳转到一个非定义的地址,然后使用 `rustsbi-qemu` 进行测试,同样进不去内核。(date: 2023-3-29 PM.) + +在链接文件中设置了新的物理地址即可解决无法运行的问题。 + +新的链接脚本如下: + +```plain +/* 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 = 0xffffffffc0200000; + +/* BASE_ADDRESS = 0x80200000; */ +__ENTRY_ADDR = 0x80200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : AT(__ENTRY_ADDR) { + stext = .; + *(.text.entry) + _copy_user_start = .; + *(.text.copy_user) + _copy_user_end = .; + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + ebss = .; + } + + PROVIDE(end = .); +} +``` + +运行结果: + +```plain +.______ __ __ _______.___________. _______..______ __ +| _ \ | | | | / | | / || _ \ | | +| |_) | | | | | | (----`---| |----`| (----`| |_) || | +| / | | | | \ \ | | \ \ | _ < | | +| |\ \----.| `--' |.----) | | | .----) | | |_) || | +| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__| + +[rustsbi] Implementation: RustSBI-QEMU Version 0.0.2 +[rustsbi-dtb] Hart count: cluster0 with 2 cores +[rustsbi] misa: RV64ACDFHIMSU +[rustsbi] mideleg: ssoft, stimer, sext (0x1666) +[rustsbi] medeleg: ima, ia, bkpt, la, sa, uecall, ipage, lpage, spage (0xb1ab) +[rustsbi] pmp0: 0x10000000 ..= 0x10001fff (rwx) +[rustsbi] pmp1: 0x80000000 ..= 0x8fffffff (rwx) +[rustsbi] pmp2: 0x0 ..= 0xffffffffffffff (---) +[rustsbi] enter supervisor 0x80200000 +addr of t: 0xffffffffc0209f40 +[INFO] logging module initialized +Hello, world! +``` + +在实现内核高半核的情况下,可以讲内核空间和用户空间分隔开,然后可以充分利用分隔出来的空间,不用担心出现内存空间重复使用的问题。 \ No newline at end of file diff --git a/modules/logging/src/lib.rs "b/docs/\345\206\205\346\240\270\350\276\223\345\207\272.md" similarity index 51% rename from modules/logging/src/lib.rs rename to "docs/\345\206\205\346\240\270\350\276\223\345\207\272.md" index e871e3eb..3863e316 100644 --- a/modules/logging/src/lib.rs +++ "b/docs/\345\206\205\346\240\270\350\276\223\345\207\272.md" @@ -1,10 +1,8 @@ -#![no_std] +# 内核输出 -use arch::console_putchar; -use core::fmt::{self, Write}; - -use log::{self, Level, LevelFilter, Log, Metadata, Record, info}; +内核使用 `log` 这个 `crate` 作为调试信息输出, 在 `Makefile` 里设置 `info` 作为默认输出级别。 +```rust struct Logger; impl Log for Logger { @@ -52,42 +50,6 @@ pub fn init() { }); info!("logging module initialized"); } +``` -#[macro_export] -macro_rules! print { - ($($arg:tt)*) => ({ - $crate::print(format_args!($($arg)*)); - }); -} - -#[macro_export] -macro_rules! println { - ($fmt:expr) => (print!(concat!($fmt, "\n"))); - ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*)); -} - -macro_rules! with_color { - ($args: ident, $color_code: ident) => {{ - format_args!("\u{1B}[{}m{}\u{1B}[0m", $color_code as u8, $args) - }}; -} - -fn print_in_color(args: fmt::Arguments, color_code: u8) { - Logger.write_fmt(with_color!(args, color_code)) - .expect("can't write color string in logging module."); -} - -pub fn print(args: fmt::Arguments) { - Logger.write_fmt(args) - .expect("can't write string in logging module."); -} - -fn level_to_color_code(level: Level) -> u8 { - match level { - Level::Error => 31, // Red - Level::Warn => 93, // BrightYellow - Level::Info => 34, // Blue - Level::Debug => 32, // Green - Level::Trace => 90, // BrightBlack - } -} +然后在其他的 `crate` 里使用 `log` 作为调试信息输出,`log` 的优点是只需要初始化一次即可到处使用。 \ No newline at end of file diff --git "a/docs/\345\206\205\346\240\270\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/\345\206\205\346\240\270\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" new file mode 100644 index 00000000..9e598e5f --- /dev/null +++ "b/docs/\345\206\205\346\240\270\351\203\250\345\210\206\346\226\207\344\273\266\347\273\223\346\236\204.md" @@ -0,0 +1,37 @@ +# 内核部分文件结构 + +``` +├── Cargo.toml +└── src +├── banner.txt +├── epoll //epoll模块实现代码 +│ └── mod.rs +├── main.rs //主函数,系统入口 +├── modules.rs //内核模块定义 +├── panic.rs //错误处理 +├── socket.rs //套接字操作 +├── syscall //系统调用实现 +│ ├── consts.rs //系统调用相关常量定义 +│ ├── fd.rs //文件描述符的相关实现 +│ ├── func.rs //系统调用相关函数实现 +│ ├── mm.rs //内存管理相关调用的实现 +│ ├── mod.rs //系统调用公共接口和函数 +│ ├── shm.rs //共享内存的系统调用实现 +│ ├── signal.rs //信号处理相关系统调用的实现 +│ ├── socket.rs //套接字相关操作的实现 +│ ├── sys.rs //其他系统调用的实现 +│ ├── task.rs //任务管理实现 +│ └── time.rs //时间和计时器的实现 +├── task_cache.rs //任务缓存的实现 +└── tasks +├── async_ops.rs //异步操作的实现 +├── elf.rs //ELF文件处理 +├── initproc.rs //初始化进程 +├── kernel.rs +├── mod.rs //任务模块实现 +└── user +├── entry.rs //用户空间代码入口点的实现 +├── mod.rs //用户空间任务实现 +└── signal.rs //用户任务信号处理 +``` + diff --git "a/docs/\345\206\205\346\240\270\351\253\230\345\215\212\346\240\270.md" "b/docs/\345\206\205\346\240\270\351\253\230\345\215\212\346\240\270.md" new file mode 100644 index 00000000..3a262f53 --- /dev/null +++ "b/docs/\345\206\205\346\240\270\351\253\230\345\215\212\346\240\270.md" @@ -0,0 +1,213 @@ +# 内核高半核 + +> 参考资料: +> +> https://github.com/rcore-os/rCore/blob/master/kernel/src/arch/riscv/boot/entry64.asm +> +> https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials + +## 尝试 + +首先尝试从 `rCore` 中获得的代码: + +```rust + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80200000 + # sp == 0x800xxxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 14 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 2. enable paging + # satp = (8 << 60) | PPN(boot_page_table_sv39) + lui t0, %hi(boot_page_table_sv39) + li t1, 0xffffffffc0000000 - 0x80000000 + sub t0, t0, t1 + srli t0, t0, 12 + li t1, 8 << 60 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + + # 3. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 4 * 8 + .global bootstacktop +bootstacktop: + + .section .data + .align 12 # page align +boot_page_table_sv39: + # 0x00000000_80000000 -> 0x80000000 (1G) + # 0xffffffff_c0000000 -> 0x80000000 (1G) + .quad 0 + .quad 0 + .quad (0x80000 << 10) | 0xcf # VRWXAD + .zero 8 * 508 + .quad (0x80000 << 10) | 0xcf # VRWXAD +``` + +linker.ld + +```ld +/* 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 = 0xffffffffc0200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + _copy_user_start = .; + *(.text.copy_user) + _copy_user_end = .; + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + ebss = .; + } + + PROVIDE(end = .); +} +``` + +但是放在内核中,并没有启动起来,由于使用是 `qemu` 提供的 `opensbi`,能够检测地址然后直接跳过去,所以跳转到一个非定义的地址,然后使用 `rustsbi-qemu` 进行测试,同样进不去内核。(date: 2023-3-29 PM.) + +在链接文件中设置了新的物理地址即可解决无法运行的问题。 + +新的链接脚本如下: + +```plain +/* 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 = 0xffffffffc0200000; + +/* BASE_ADDRESS = 0x80200000; */ +__ENTRY_ADDR = 0x80200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : AT(__ENTRY_ADDR) { + stext = .; + *(.text.entry) + _copy_user_start = .; + *(.text.copy_user) + _copy_user_end = .; + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + ebss = .; + } + + PROVIDE(end = .); +} +``` + +运行结果: + +```plain +.______ __ __ _______.___________. _______..______ __ +| _ \ | | | | / | | / || _ \ | | +| |_) | | | | | | (----`---| |----`| (----`| |_) || | +| / | | | | \ \ | | \ \ | _ < | | +| |\ \----.| `--' |.----) | | | .----) | | |_) || | +| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__| + +[rustsbi] Implementation: RustSBI-QEMU Version 0.0.2 +[rustsbi-dtb] Hart count: cluster0 with 2 cores +[rustsbi] misa: RV64ACDFHIMSU +[rustsbi] mideleg: ssoft, stimer, sext (0x1666) +[rustsbi] medeleg: ima, ia, bkpt, la, sa, uecall, ipage, lpage, spage (0xb1ab) +[rustsbi] pmp0: 0x10000000 ..= 0x10001fff (rwx) +[rustsbi] pmp1: 0x80000000 ..= 0x8fffffff (rwx) +[rustsbi] pmp2: 0x0 ..= 0xffffffffffffff (---) +[rustsbi] enter supervisor 0x80200000 +addr of t: 0xffffffffc0209f40 +[INFO] logging module initialized +Hello, world! +``` + +在实现内核高半核的情况下,可以讲内核空间和用户空间分隔开,然后可以充分利用分隔出来的空间,不用担心出现内存空间重复使用的问题。 diff --git "a/docs/\345\215\216\345\261\261\346\264\276\345\274\200\345\217\221\346\235\277SD\345\215\241\351\251\261\345\212\250\350\256\276\350\256\241.md" "b/docs/\345\215\216\345\261\261\346\264\276\345\274\200\345\217\221\346\235\277SD\345\215\241\351\251\261\345\212\250\350\256\276\350\256\241.md" new file mode 100644 index 00000000..96d4ddc6 --- /dev/null +++ "b/docs/\345\215\216\345\261\261\346\264\276\345\274\200\345\217\221\346\235\277SD\345\215\241\351\251\261\345\212\250\350\256\276\350\256\241.md" @@ -0,0 +1,554 @@ +# 华山派开发板SD卡驱动设计 + +为在华山派CV1811h上运行**ByteOS**并顺利运行测试,我们编写了一应用于华山派开发板的SD卡驱动,以下是详细设计 + +``` +├── cv1811-sd //支持华山派cv1811h的SD卡驱动 +│   ├── Cargo.toml +│   └── src +│   ├── consts.rs //相关常量的定义 +│   ├── lib.rs //驱动主体 +│   └── utils.rs //寄存器读写操作定义 +``` + +在`consts.rs`中我们定义了一些编写驱动所需的常量和寄存器 + +例如: + +```rust +pub const TOP_BASE: usize = 0xffff_ffc0_030_00000; +pub const SD_DRIVER_ADDR: usize = 0xffff_ffc0_0431_0000; +pub const SOFT_REST_BASE_ADDR: usize = 0xffff_ffc0_0300_3000; +pub const PINMUX_BASE: usize = 0xffff_ffc0_0300_1000; +``` + +- `TOP_BASE`:顶层基地址,用于与其他组件进行通信。 +- `SD_DRIVER_ADDR`:SD卡驱动的基地址。 +- `SOFT_REST_BASE_ADDR`:软件复位基地址,用于执行软件复位操作。 +- `PINMUX_BASE`:引脚复用基地址,用于配置引脚的功能。 + +```rust +pub struct EmmcCtrl(u32) { + emmc_func_en: u1, + latancy_1t: u1, + clk_free_en: u1, + disable_data_crc_check: u1, + reserved: u1, + emmc_rstn: u1, + emmc_rstn_oen: u1, + reserved1: u2, + cqe_algo_sel: u1, + cqe_prefetch_disable: u1, + reserved2: u2, + timer_clk_sel: u1, + reserved3: u18 + } +``` + +`EmmcCtrl`:这个结构体表示eMMC控制器的控制寄存器。它使用了一个32位的整数来存储以下字段: + +- `emmc_func_en`、`latancy_1t`、`clk_free_en`、`disable_data_crc_check`、`reserved`、`emmc_rstn`、`emmc_rstn_oen`、`reserved1`、`cqe_algo_sel`、`cqe_prefetch_disable`、`reserved2`、`timer_clk_sel`和`reserved3`:这些字段是控制寄存器中的各个位字段,用于控制eMMC控制器的不同功能和选项。 + +同时还定义了错误类型,指令类型和信息输出 + +```rust +#[derive(Debug)] +pub enum CmdError { + IntError, +} + +pub enum CommandType { + CMD(u8), + ACMD(u8), +} + +impl CommandType { + pub fn num(&self) -> u8 { + match self { + CommandType::CMD(t) => *t, + CommandType::ACMD(t) => *t, + } + } +} +``` + +这段代码定义了两个枚举类型,一个用于表示命令执行过程中的错误,另一个用于表示命令的类型。并且为 `CmdError` 枚举类型自动实现了 `Debug` trait,以便于调试和打印错误信息。 + +`utils.rs`设计了针对寄存器的读写操作 + +```rust +use crate::consts::{PresentState, SD_DRIVER_ADDR}; +use bit_struct::*; + +pub fn reg_transfer(offset: usize) -> &'static mut T { + unsafe { ((SD_DRIVER_ADDR + offset) as *mut T).as_mut().unwrap() } +} + +/// check the sdcard that was inserted +pub fn check_sd() -> bool { + let present_state = reg_transfer::(0x24); + present_state.card_inserted().get() == u1!(1) +} + +pub fn mmio_clrsetbits_32(addr: *mut u32, clear: u32, set: u32) { + unsafe { + *addr = (*addr & !clear) | set; + } +} + +pub fn mmio_clearbits_32(addr: *mut u32, clear: u32) { + unsafe { + *addr = *addr & !clear; + } +} + +pub fn mmio_setbits_32(addr: *mut u32, set: u32) { + unsafe { + *addr = *addr | set; + } +} + +pub fn mmio_write_32(addr: *mut u32, value: u32) { + unsafe { + *addr = value; + } +} + +pub fn mmio_read_32(addr: *mut u32) -> u32 { + unsafe { *addr } +} +``` + +1. `use crate::consts::{PresentState, SD_DRIVER_ADDR};`:这行代码引入了 `consts` 模块中的 `PresentState` 和 `SD_DRIVER_ADDR` 常量。`PresentState` 是一个寄存器状态的结构体,`SD_DRIVER_ADDR` 是一个寄存器的基地址。 +2. `pub fn reg_transfer(offset: usize) -> &'static mut T`:这是一个泛型函数,用于在给定偏移量的基础上返回一个可变引用。该函数将基地址 `SD_DRIVER_ADDR` 与偏移量相加,然后将其转换为一个指向类型 `T` 的可变引用。这个函数使用了 `unsafe` 关键字,因为它涉及到原始指针的操作和不可变引用的可变化。 +3. `pub fn check_sd() -> bool`:这个函数用于检查是否插入了SD卡。它通过调用 `reg_transfer()` 函数获取 `PresentState` 寄存器的可变引用,并使用 `card_inserted()` 方法获取 `card_inserted` 字段的值。如果 `card_inserted` 字段的值为1,表示SD卡已插入,函数返回 `true`;否则,返回 `false`。 +4. `pub fn mmio_clrsetbits_32(addr: *mut u32, clear: u32, set: u32)`:这个函数用于对32位寄存器进行复位和设置位操作。它使用原始指针 `addr` 来访问寄存器,将寄存器的值与 `clear` 进行按位取反的与操作,再与 `set` 进行按位或操作。最终的结果被存储回寄存器。 +5. `pub fn mmio_clearbits_32(addr: *mut u32, clear: u32)`:这个函数用于清除32位寄存器中的指定位。它使用原始指针 `addr` 来访问寄存器,将寄存器的值与 `clear` 进行按位取反的与操作,将指定位清零。 +6. `pub fn mmio_setbits_32(addr: *mut u32, set: u32)`:这个函数用于设置32位寄存器中的指定位。它使用原始指针 `addr` 来访问寄存器,将寄存器的值与 `set` 进行按位或操作,将指定位设置为1。 +7. `pub fn mmio_write_32(addr: *mut u32, value: u32)`:这个函数用于将指定值写入32位寄存器。它使用原始指针 `addr` 来访问寄存器,将指定值 `value` 直接存储到寄存器中。 +8. `pub fn mmio_read_32(addr: *mut u32) -> u32`:这个函数用于从32位寄存器中读取值。它使用原始指针 `addr` 来访问寄存器,并返回寄存器中的值。 + +`lib.rs`是SD卡驱动的主要部分,实现了对SD卡数据的读取写入等功能 + +```rust +pub fn read_block(block_id: u32, data: &mut [u8]) -> Result<(), CmdError> { + cmd_transfer(CommandType::CMD(17), block_id, 1)?; + read_buff(data)?; + let res = wait_for_xfer_done(); + mmio_write_32( + (SD_DRIVER_ADDR + 0x30) as _, + mmio_read_32((SD_DRIVER_ADDR + 0x30) as _), + ); + res +} + +/// write a block to the sdcard. +pub fn write_block(block_id: u32, data: &[u8]) -> Result<(), CmdError> { + cmd_transfer(CommandType::CMD(24), block_id, 1)?; + // read_buff(data)?; + write_buff(data)?; + let res = wait_for_xfer_done(); + mmio_write_32( + (SD_DRIVER_ADDR + 0x30) as _, + mmio_read_32((SD_DRIVER_ADDR + 0x30) as _), + ); + res +} + +pub fn reset_config() { + unsafe { + // disable power + // NOTE: This will close the bus power, but i don't how to restart again. + power_config(PowerLevel::Close); + + // reset + mmio_clearbits_32( + (SD_DRIVER_ADDR + 0x2c) as *mut u32, + (1 << 24) | (1 << 25) | (1 << 26), + ); + for _ in 0..0x1000 { + asm!("nop") + } + // enable power + power_config(PowerLevel::V33); + + // high_speed and data width 4 bit + // mmio_setbits_32((SD_DRIVER_ADDR + 0x28) as _, (1 << 1) | (1 << 2)); + mmio_setbits_32((SD_DRIVER_ADDR + 0x28) as _, 1 << 2); + + // *((SD_DRIVER_ADDR + 0x28) as *mut u8) |= 1 << 3; + } +} + +pub fn wait_for_cmd_done() -> Result<(), CmdError> { + let norm_int_sts = reg_transfer::(0x30); + loop { + if norm_int_sts.err_int().get() == true { + mmio_write_32((SD_DRIVER_ADDR + 0x30) as _, 1 << 15); + break Err(CmdError::IntError); + } + if norm_int_sts.cmd_cmpl().get() == true { + mmio_write_32((SD_DRIVER_ADDR + 0x30) as _, 1 << 0); + break Ok(()); + } + for _ in 0..1 { + unsafe { asm!("nop") } + } + } +} +``` + +1. `pub fn read_block(block_id: u32, data: &mut [u8]) -> Result<(), CmdError>`:这个函数用于从SD卡中读取一个数据块。它接受一个 `block_id` 参数表示要读取的数据块编号,以及一个可变引用 `data` 表示存储读取数据的缓冲区。函数内部调用了 `cmd_transfer()` 函数发送读块的命令(使用命令类型 `CommandType::CMD(17)`),然后调用了 `read_buff()` 函数读取数据块内容到缓冲区中。最后,函数调用了 `wait_for_xfer_done()` 函数等待传输完成,并返回传输结果。 +2. `pub fn write_block(block_id: u32, data: &[u8]) -> Result<(), CmdError>`:这个函数用于向SD卡写入一个数据块。它接受一个 `block_id` 参数表示要写入的数据块编号,以及一个 `data` 参数表示要写入的数据块内容。函数内部调用了 `cmd_transfer()` 函数发送写块的命令(使用命令类型 `CommandType::CMD(24)`),然后调用了 `write_buff()` 函数将数据块内容写入到SD卡中。最后,函数调用了 `wait_for_xfer_done()` 函数等待传输完成,并返回传输结果。 +3. `pub fn reset_config()`:这个函数用于重置SD卡的配置。函数内部使用了 `unsafe` 关键字,因为它涉及到对寄存器的直接操作。函数首先关闭SD卡的电源(通过调用 `power_config()` 函数),然后对SD卡的寄存器进行复位操作,包括清除特定位的状态、延时等待一段时间,最后重新打开SD卡的电源,并设置高速模式和数据宽度为4位。 +4. `pub fn wait_for_cmd_done() -> Result<(), CmdError>`:这个函数用于等待命令执行完成。函数内部使用了一个循环来检查命令执行的状态。它通过调用 `reg_transfer()` 函数获取命令状态寄存器的可变引用,并在循环中检查错误状态和命令完成状态。如果出现错误,函数将返回 `Err(CmdError::IntError)`;如果命令完成,函数将返回 `Ok(())`。在每次循环迭代中,函数使用 `mmio_write_32()` 函数清除中断状态位,并使用 `asm!("nop")` 指令进行短暂延时。 + +```rust +pub fn wait_for_xfer_done() -> Result<(), CmdError> { + let norm_int_sts = reg_transfer::(0x30); + loop { + if norm_int_sts.xfer_cmpl().get() == true { + mmio_write_32((SD_DRIVER_ADDR + 0x30) as _, 1 << 1); + break Ok(()); + } + if norm_int_sts.err_int().get() == true { + mmio_write_32((SD_DRIVER_ADDR + 0x30) as _, 1 << 15); + break Err(CmdError::IntError); + } + for _ in 0..1 { + unsafe { asm!("nop") } + } + } +} + +pub fn cmd_transfer(cmd: CommandType, arg: u32, blk_cnt: u32) -> Result<(), CmdError> { + let present_state = reg_transfer::(0x24); + + while present_state.cmd_inhibit_dat().get() == true + || present_state.cmd_inhibit_dat().get() == true + {} + + let mut flags: u32 = (cmd.num() as u32) << 24; + + const BLK_CNT_EN: u32 = 1 << 1; + const XFER_READ: u32 = 1 << 4; + const DATA_PRESENT: u32 = 1 << 21; + const L48: u32 = 2 << 16; + const L48_BUSY: u32 = 2 << 16; + const L136: u32 = 1 << 16; + const CRC_CHECK_EN: u32 = 1 << 19; + const INX_CHECK_EN: u32 = 1 << 20; + + if blk_cnt > 0 { + // set blk size and blk count + mmio_write_32((SD_DRIVER_ADDR + 0x04) as _, 0x200 | (blk_cnt << 16)); + flags |= BLK_CNT_EN; + } + + flags |= match cmd { + CommandType::CMD(17) => DATA_PRESENT | XFER_READ, + CommandType::CMD(24) => DATA_PRESENT, + CommandType::ACMD(51) => DATA_PRESENT | XFER_READ, + _ => 0, + }; + + flags |= match cmd { + // R1 + CommandType::ACMD(6) + | CommandType::ACMD(42) + | CommandType::ACMD(51) + | CommandType::CMD(17) + | CommandType::CMD(24) + | CommandType::CMD(8) + | CommandType::CMD(16) + | CommandType::CMD(7) => L48 | CRC_CHECK_EN | INX_CHECK_EN, + // R2 + CommandType::CMD(2) | CommandType::CMD(9) => L136 | CRC_CHECK_EN, + // R3 + CommandType::ACMD(41) | CommandType::CMD(58) => L48, + // R6 + CommandType::CMD(3) => L48_BUSY | CRC_CHECK_EN | INX_CHECK_EN, + _ => 0, + }; + + unsafe { + // set blk cnt + *((SD_DRIVER_ADDR + 0x06) as *mut u8) = 0; + // set timeout time + *((SD_DRIVER_ADDR + 0x2e) as *mut u8) = 0xe; + *((SD_DRIVER_ADDR + 0x30) as *mut u32) = 0xF3FFFFFF; + *((SD_DRIVER_ADDR + 0x8) as *mut u32) = arg; + *((SD_DRIVER_ADDR + 0xc) as *mut u32) = flags; + } + + wait_for_cmd_done()?; + + let resp1_0 = *reg_transfer::(0x10); + let resp3_2 = *reg_transfer::(0x14); + let resp5_4 = *reg_transfer::(0x18); + let resp7_6 = *reg_transfer::(0x1c); + + // this is used to print result and consume ptr. + // There needs to read the resp regs after cmd. + log::trace!( + "resp: {:#x} {:#x} {:#x} {:#x}", + resp1_0, + resp3_2, + resp5_4, + resp7_6 + ); + + Ok(()) +} +``` + +1. `pub fn wait_for_xfer_done() -> Result<(), CmdError>`:这个函数用于等待数据传输完成。函数内部使用一个循环来检查传输完成的状态。它首先调用 `reg_transfer()` 函数获取传输状态寄存器的可变引用,并在循环中检查传输完成状态和错误状态。如果传输完成,函数将调用 `mmio_write_32()` 函数写入中断状态位,并返回 `Ok(())`;如果出现错误,函数将调用 `mmio_write_32()` 函数写入中断状态位,并返回 `Err(CmdError::IntError)`。在每次循环迭代中,函数使用 `asm!("nop")` 指令进行短暂延时。 +2. `pub fn cmd_transfer(cmd: CommandType, arg: u32, blk_cnt: u32) -> Result<(), CmdError>`:这个函数用于发送命令到SD卡。函数接受一个 `cmd` 参数表示要发送的命令类型,一个 `arg` 参数表示命令参数,以及一个 `blk_cnt` 参数表示块计数(用于读写命令)。函数内部首先通过调用 `reg_transfer()` 函数获取当前的传输状态寄存器,并在一个循环中等待直到命令控制器可用。然后,函数根据命令类型和块计数设置不同的标志位,并将这些标志位与命令号合并为 `flags` 变量。接下来,根据命令类型设置其他的标志位。在 `flags` 设置完成后,函数使用 `unsafe` 关键字访问寄存器,在适当的寄存器中写入命令相关的参数和标志位。然后,函数调用 `wait_for_cmd_done()` 函数等待命令执行完成。最后,函数使用 `reg_transfer()` 函数读取响应寄存器的值,并将其打印出来。 + +```rust +pub fn pad_settings() { + mmio_write_32((TOP_BASE + REG_TOP_SD_PWRSW_CTRL) as _, 0x9); + + // let val: u8 = (bunplug) ? 0x3 : 0x0; + let reset = false; + + let val = if reset { 0x3 } else { 0x0 }; + + mmio_write_32(PAD_SDIO0_CD_REG as _, 0x0); + mmio_write_32(PAD_SDIO0_PWR_EN_REG as _, 0x0); + mmio_write_32(PAD_SDIO0_CLK_REG as _, val as _); + mmio_write_32(PAD_SDIO0_CMD_REG as _, val as _); + mmio_write_32(PAD_SDIO0_D0_REG as _, val as _); + mmio_write_32(PAD_SDIO0_D1_REG as _, val as _); + mmio_write_32(PAD_SDIO0_D2_REG as _, val as _); + mmio_write_32(PAD_SDIO0_D3_REG as _, val as _); + + if reset { + mmio_clrsetbits_32( + REG_SDIO0_PWR_EN_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_PWR_EN_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CD_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CD_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CLK_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CLK_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CMD_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CMD_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT1_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT1_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT0_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT0_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT2_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT2_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT3_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT3_PAD_RESET << REG_SDIO0_PAD_SHIFT, + ); + } else { + mmio_clrsetbits_32( + REG_SDIO0_PWR_EN_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_PWR_EN_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CD_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CD_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CLK_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CLK_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_CMD_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_CMD_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT1_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT1_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT0_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT0_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT2_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT2_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + + mmio_clrsetbits_32( + REG_SDIO0_DAT3_PAD_REG as _, + REG_SDIO0_PAD_CLR_MASK, + REG_SDIO0_DAT3_PAD_VALUE << REG_SDIO0_PAD_SHIFT, + ); + } +} +``` + +这段代码是SD卡驱动中的 `pad_settings()` 函数,用于设置SD卡的引脚配置。 + +首先,代码通过调用 `mmio_write_32()` 函数将值 `0x9` 写入寄存器 `TOP_SD_PWRSW_CTRL`,从而设置SD卡的电源开关控制。 + +接下来,代码根据 `reset` 变量的值判断是否进行复位操作。如果 `reset` 为真,则将变量 `val` 设置为 `0x3`,否则设置为 `0x0`。 + +然后,代码使用 `mmio_write_32()` 函数将不同的值写入一系列与SD卡引脚相关的寄存器。具体来说,将 `0x0` 写入 `PAD_SDIO0_CD_REG` 寄存器、`PAD_SDIO0_PWR_EN_REG` 寄存器以及 `PAD_SDIO0_CLK_REG`、`PAD_SDIO0_CMD_REG`、`PAD_SDIO0_D0_REG`、`PAD_SDIO0_D1_REG`、`PAD_SDIO0_D2_REG`、`PAD_SDIO0_D3_REG` 寄存器。这些寄存器控制着SD卡引脚的功能和电平状态。 + +如果 `reset` 为真,代码将执行复位操作。对于每个引脚,代码使用 `mmio_clrsetbits_32()` 函数将相应的复位值写入寄存器,通过位掩码和位移操作将复位值放置在正确的位置。 + +如果 `reset` 为假,代码将设置引脚为非复位状态。对于每个引脚,代码使用 `mmio_clrsetbits_32()` 函数将相应的非复位值写入寄存器,通过位掩码和位移操作将非复位值放置在正确的位置。 + +这样,`pad_settings()` 函数完成了SD卡引脚的配置,根据 `reset` 变量的值选择进行复位或非复位操作,并将相应的值写入对应的寄存器,以控制SD卡的引脚状态。 + +```rust +pub fn init() -> Result<(), CmdError> { + // Initialize sd card gpio + if check_sd() { + pad_settings(); + reset_config(); + + power_config(PowerLevel::V18); + set_clock(4); + + // sdcard initialize. + cmd_transfer(CommandType::CMD(0), 0, 0)?; + cmd_transfer(CommandType::CMD(8), 0x1aa, 0)?; + // wait for initialization to end. + loop { + cmd_transfer(CommandType::CMD(55), 0, 0)?; + cmd_transfer( + CommandType::ACMD(41), + 0x4000_0000 | 0x0030_0000 | (0x1FF << 15), + 0, + )?; + + if *reg_transfer::(0x10) >> 31 == 1 { + break; + } + for _ in 0..0x100_0000 { + unsafe { asm!("nop") } + } + } + log::debug!("init finished"); + // // get card and select + cmd_transfer(CommandType::CMD(2), 0, 0)?; + cmd_transfer(CommandType::CMD(3), 0, 0)?; + log::debug!("start to read scd"); + let rsa = *reg_transfer::(0x10) & 0xffff0000; + cmd_transfer(CommandType::CMD(9), rsa, 0)?; // get scd reg + log::debug!("start to select card"); + cmd_transfer(CommandType::CMD(7), rsa, 0)?; // select card + + log::debug!("start to switch to 4 bit bus"); + // support 4 bit bus width. + cmd_transfer(CommandType::CMD(55), rsa, 0)?; + cmd_transfer(CommandType::ACMD(6), 2, 0)?; + unsafe { + *((SD_DRIVER_ADDR + 0x28) as *mut u8) |= 2; + } + clk_en(false); + } + Ok(()) +} +``` + +这段代码是SD卡驱动中的 `init()` 函数,用于初始化SD卡。 + +首先,代码通过调用 `check_sd()` 函数检查SD卡是否存在。如果存在,则执行以下初始化步骤: + +1. 调用 `pad_settings()` 函数配置SD卡的引脚。 +2. 调用 `reset_config()` 函数对SD卡进行复位配置。 +3. 调用 `power_config(PowerLevel::V18)` 函数设置SD卡的电源电压为1.8V。 +4. 调用 `set_clock(4)` 函数设置SD卡的时钟频率为4。 + +接下来,代码执行SD卡的初始化过程。具体步骤如下: + +1. 发送命令 `CMD(0)` 进行SD卡初始化。 + +2. 发送命令 `CMD(8)` 并传递参数 `0x1aa`,用于与SD卡进行通信。 + +3. 进入一个循环,不断发送命令 + + ``` + CMD(55) + ``` + + 和 + + ``` + ACMD(41) + ``` + + 直到初始化结束。在发送 + + ``` + ACMD(41) + ``` + + 命令时,传递了一些参数,包括位掩码和位移操作。循环检查寄存器的值,如果满足条件则跳出循环,否则等待一段时间。 + + - 在循环中,通过 `reg_transfer()` 函数读取寄存器的值,并进行一些位操作。 + - 使用 `asm!("nop")` 指令进行空操作,等待一段时间。 + +初始化完成后,代码输出日志信息并继续执行以下步骤: + +1. 发送命令 `CMD(2)` 获取SD卡的CID信息。 +2. 发送命令 `CMD(3)` 进入SD卡的数据传输状态。 +3. 输出日志信息。 +4. 发送命令 `CMD(9)` 并传递参数 `rsa`,用于获取SD卡的SCR寄存器的值。 +5. 发送命令 `CMD(7)` 并传递参数 `rsa`,选择SD卡。 +6. 输出日志信息。 +7. 发送命令 `CMD(55)` 和 `ACMD(6)`,用于支持4位数据总线宽度。 +8. 使用 `*((SD_DRIVER_ADDR + 0x28) as *mut u8) |= 2` 指令将某个地址处的值的特定位设置为1。 +9. 调用 `clk_en(false)` 函数关闭时钟使能。 + +最后,函数返回 `Ok(())` 表示初始化成功。 + + + +为了更好地完成任务,我们在编写驱动时特别关注了以下工作: + +1. **引脚配置和复位设置**:代码通过调用 `pad_settings()` 函数对SD卡的引脚进行配置,以及调用 `reset_config()` 函数对SD卡进行复位设置。这些步骤确保SD卡与系统正确连接,并处于正确的初始状态。 +2. **电源配置**:代码通过调用 `power_config()` 函数对SD卡的电源电压进行配置。这允许驱动程序为SD卡提供正确的电源电压,以确保其正常工作。 +3. **时钟设置**:代码调用 `set_clock()` 函数设置SD卡的时钟频率。正确的时钟设置对于SD卡的数据传输和通信至关重要。 +4. **SD卡初始化过程**:代码执行了SD卡的初始化过程,包括发送特定的命令和参数以与SD卡进行通信和配置。这确保了SD卡能够正确地与系统进行交互,并准备好进行后续的数据传输操作。 +5. **日志输出**:代码使用日志输出来提供关键的调试信息,帮助开发人员了解SD卡初始化过程的状态和进展。这对于故障排除和性能优化非常有用。 +6. **4位数据总线宽度支持**:代码通过发送命令 `CMD(55)` 和 `ACMD(6)`,以及特定的位操作,支持SD卡的4位数据总线宽度。这可以提高数据传输速度和性能。 + diff --git "a/docs/\345\240\206\345\210\206\351\205\215\345\231\250.md" "b/docs/\345\240\206\345\210\206\351\205\215\345\231\250.md" new file mode 100644 index 00000000..5bdf7870 --- /dev/null +++ "b/docs/\345\240\206\345\210\206\351\205\215\345\231\250.md" @@ -0,0 +1,34 @@ +# 堆分配器 + +为了使用 `Rust` 的 `alloc`,因此在内核中需要实现一个针对 `Rust` 语言的分配器,且实现 `GlobalAlloc` 接口,这里我们采用已经比较完善的 `buddy_system_allocator`。 + +## 高半核的好处 + +在我们已经实现了 `higher-half kernel` 的基础上,我们能够在整个程序的尾部(虚拟内存)添加一个堆分配器,即内核堆,在堆分配器内存不够的时候会在内核中出发页表缺失异常,然后在异常处理函数中进行页表的分配和映射,然后返回相应的位置即可继续运行,栈同理。 + +在 `RISCV` 的 `Sv39` 中,内核的 `39..63 bits` 需要与第 `38bit` 保持一致。并且一个页表里可以存放 512 个页表项,换算成十六进制就是 0x200。因此可以把前 0x100 个也就是 256 G作为用户空间,后面的 0x100 个作为内核空间。 + +```rust +#![no_std] + +use buddy_system_allocator::LockedHeap; + +// 堆大小 +const HEAP_SIZE: usize = 0x0008_0000; + +// 堆空间 +static mut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE]; + +// 堆内存分配器 +#[global_allocator] +static HEAP_ALLOCATOR: LockedHeap<64> = LockedHeap::empty(); + +// 初始化堆内存分配器 +pub fn init() { + unsafe { + HEAP_ALLOCATOR + .lock() + .init(HEAP.as_ptr() as usize, HEAP_SIZE); + } +} +``` \ No newline at end of file diff --git "a/docs/\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/docs/\346\200\247\350\203\275\344\274\230\345\214\226.md" new file mode 100644 index 00000000..af83ed49 --- /dev/null +++ "b/docs/\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -0,0 +1,11 @@ +# 性能优化 + +我们在 ByteOS 中实现了许多对于内核性能的优化措施,比如 `COW(Copy On Write)`, `内存延迟分配`, `文件缓存`, `文件树` 等。 + +我们为 `UserTask` 提供了一个 `cow_fork` 接口,当我们需要 `fork` 一个程序的时候我们可以使用这个接口进行复制。然后在内存触发页中断的时候进行复制。 + +我们在 `mmap` 的时候先给程序分配一些空间,但是并不分配内存给他,在触发页中断之后我们会根据触发中断的地址进行判断,如果是已经分配的内存,那么将会申请内存给这个程序,将空间进行映射。 + +我们发现有些程序频繁被执行,但是执行时间比较短,所以我们采用 `文件缓冲` 的方式进行处理,后来我们衍生出了 "进程模板",即采用一个结构存储程序执行需要的页表等结构,在执行时使用类似 `cow_fork` 的机制分配给他,减少了频繁执行某些程序的页表释放操作,那么性能将大大提升。 + +为了提高我们 OS 的文件检索性能,我们构建了 `DentryTree` 的结构。在检索文件时,现在 `DentryTree` 上检索文件的存在,如果文件存在,那么直接进行复制。对于频繁的文件检索和操作性能将大大提升。如 `Stat`, `StatFS`。 \ No newline at end of file diff --git "a/docs/\346\226\207\344\273\266\347\263\273\347\273\237.md" "b/docs/\346\226\207\344\273\266\347\263\273\347\273\237.md" new file mode 100644 index 00000000..10d75f88 --- /dev/null +++ "b/docs/\346\226\207\344\273\266\347\263\273\347\273\237.md" @@ -0,0 +1,759 @@ +# 文件系统 + +``` +├── Cargo.toml +└── src + ├── cache.rs //缓存相关实现 + ├── dentry.rs //目录项相关实现 + ├── fatfs_shim.rs //FAT shim层实现 + ├── lib.rs //主文件 + ├── mount.rs //挂载相关实现 + └── pipe.rs //管道相关实现 +``` + +#### 主要代码实现 + +```rust +pub type File = Arc; + +pub use vfscore::{ + FileType, INodeInterface, OpenFlags, PollEvent, PollFd, SeekFrom, Stat, StatFS, StatMode, + TimeSpec, VfsError, UTIME_NOW, UTIME_OMIT, +}; +pub static FILESYSTEMS: LazyInit>> = LazyInit::new(); + +pub fn build_devfs(filesystems: &Vec<(Arc, &str)>) -> Arc { + let dev_sdxs: Vec<_> = filesystems + .iter() + .enumerate() + .map(|(i, _x)| { + Arc::new(Sdx::new( + i, + |fs_id, path| mount(String::from(path), fs_id), + |_fs_id, path| umount(path), + )) + }) + .collect(); + let mut dev_dir = DevDir::new(); + + // TODO: add fs normal, not fixed. + dev_dir.add("sda", dev_sdxs[0].clone()); + + DevFS::new_with_dir(dev_dir) +} + +pub fn init() { + info!("fs module initialized"); + + // TODO: Identify the filesystem at the device. + let mut filesystems: Vec<(Arc, &str)> = Vec::new(); + if get_blk_devices().len() > 0 { + filesystems.push((Fat32FileSystem::new(0), "/")); + } else { + filesystems.push((RamFs::new(), "/")); + } + + filesystems.push((build_devfs(&filesystems), "/dev")); + filesystems.push((RamFs::new(), "/tmp")); + filesystems.push((RamFs::new(), "/dev/shm")); + filesystems.push((RamFs::new(), "/tmp_home")); + filesystems.push((RamFs::new(), "/var")); + filesystems.push((ProcFS::new(), "/proc")); + // filesystems.push((RamFs::new(), "/bin")); + + // mount to FILESYSTEMS + FILESYSTEMS.init_by(filesystems.iter().map(|(fs, _)| fs.clone()).collect()); + + // init mount points + info!("create fatfs mount file"); + { + // create monnt point dev, tmp + // let fs = &filesystems[0].0; + // let rootfs = filesystems[0].0.root_dir(); + let rootfs = get_filesystem(0).root_dir(); + rootfs.mkdir("dev").expect("can't create devfs dir"); + rootfs.mkdir("tmp").expect("can't create tmp dir"); + // rootfs.mkdir("lib").expect("can't create lib dir"); + rootfs.mkdir("tmp_home").expect("can't create tmp_home dir"); + rootfs.mkdir("var").expect("can't create var dir"); + rootfs.mkdir("proc").expect("can't create proc dir"); + rootfs.mkdir("bin").expect("can't create var dir"); + } + for (i, (_, mount_point)) in filesystems.iter().enumerate() { + mount(mount_point.to_string(), i).expect(&format!("can't mount fs_{i} {mount_point}")); + } + { + // let cache_file = vec!["busybox", "entry-static.exe", "runtest.exe"]; + let rootfs = get_filesystem(0).root_dir(); + let tmpfs = mount::open("/tmp_home").expect("can't open /tmp_home"); + for file in rootfs.read_dir().expect("can't read files") { + tmpfs + .link( + &file.filename, + rootfs.open(&file.filename, OpenFlags::NONE).unwrap(), + ) + .expect("can't link file to tmpfs"); + } + + mount::open("/var") + .expect("can't open /var") + .mkdir("tmp") + .expect("can't create tmp dir"); + + // mount::open("/bin") + // .expect("can't open /bin") + // .link( + // "sleep", + // mount::open("busybox").expect("not hava busybox file"), + // ) + // .expect("can't link busybox to /bin/sleep"); + } + cache::init(); +} +``` + +- `pub type File = Arc`: 定义了一个`File`类型,它是一个`Arc`指针,指向实现了`INodeInterface` trait的对象。这表示文件在文件系统中的抽象表示。 +- `pub use vfscore::{...}`: 导入了一些与文件系统相关的功能和类型,例如文件类型、打开标志、文件状态、错误类型等。 +- `pub static FILESYSTEMS: LazyInit>> = LazyInit::new()`: 定义了一个静态变量`FILESYSTEMS`,它是一个延迟初始化的`Vec`,其中的元素是实现了`FileSystem` trait的对象的`Arc`指针。这个变量用于存储文件系统的集合。 +- `pub fn build_devfs(filesystems: &Vec<(Arc, &str)>) -> Arc`: 构建并返回一个`DevFS`的`Arc`指针。该函数接受一个文件系统的元组列表作为参数,每个元组包含一个实现了`FileSystem` trait的对象的`Arc`指针和一个字符串表示挂载点。在函数内部,根据提供的文件系统列表创建了一个`DevDir`对象,并添加了一个名为"sda"的设备节点,该节点引用了第一个文件系统。 +- `pub fn init()`: 初始化函数,用于初始化文件系统。在函数内部,首先创建了一个空的文件系统列表`filesystems`。接下来,根据检测到的块设备数量决定使用哪种文件系统,并将其添加到`filesystems`列表中。然后,通过调用`build_devfs`函数构建了一个`DevFS`对象,并将其添加到`filesystems`列表中。随后,根据`filesystems`列表中的文件系统信息,依次进行挂载操作。最后,进行一些其他初始化操作,如创建文件系统的挂载点、链接文件到临时文件系统等。 + +这段代码展示了文件系统的初始化过程,包括构建`DevFS`和其他文件系统的初始化、挂载和一些额外的操作。 + +```rust +pub fn get_filesystem(id: usize) -> &'static Arc { + &FILESYSTEMS[id] +} + +pub struct WaitBlockingRead<'a>(pub Arc, pub &'a mut [u8], pub usize); + +impl<'a> Future for WaitBlockingRead<'a> { + type Output = VfsResult; + + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let offset = self.2; + let file = self.0.clone(); + let buffer = &mut self.1; + match file.readat(offset, *buffer) { + Ok(rsize) => Poll::Ready(Ok(rsize)), + Err(err) => { + if let VfsError::Blocking = err { + Poll::Pending + } else { + Poll::Ready(Err(err)) + } + } + } + } +} + +pub struct WaitBlockingWrite<'a>(pub Arc, pub &'a [u8], pub usize); + +impl<'a> Future for WaitBlockingWrite<'a> { + type Output = VfsResult; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let offset = self.2; + let file = self.0.clone(); + let buffer = &self.1; + + match file.writeat(offset, *buffer) { + Ok(wsize) => Poll::Ready(Ok(wsize)), + Err(err) => { + if let VfsError::Blocking = err { + Poll::Pending + } else { + Poll::Ready(Err(err)) + } + } + } + } +} +``` + +这段代码包括两个结构体和它们的实现,用于处理阻塞式读取和写入操作的异步处理。 + +- `pub fn get_filesystem(id: usize) -> &'static Arc`: 这个函数接受一个索引值`id`,返回一个指向文件系统的`Arc`指针的静态引用。它通过索引访问`FILESYSTEMS`静态变量中的文件系统。 +- `pub struct WaitBlockingRead<'a>(pub Arc, pub &'a mut [u8], pub usize)`: 这是一个结构体,包含了一个文件的`Arc`指针、一个可变的字节数组引用和一个偏移量。它用于表示阻塞式读取操作的异步处理。 + - `impl<'a> Future for WaitBlockingRead<'a>`: 这是`WaitBlockingRead`结构体的`Future`实现。它定义了异步操作的返回类型和`poll`方法。在`poll`方法中,根据给定的偏移量,调用文件的`readat`方法来进行读取操作。如果读取成功,则返回带有读取字节数的`VfsResult`。如果遇到阻塞错误,则返回`Poll::Pending`表示异步操作仍在进行中。如果遇到其他错误,则返回带有错误信息的`VfsResult`。 +- `pub struct WaitBlockingWrite<'a>(pub Arc, pub &'a [u8], pub usize)`: 这是另一个结构体,与`WaitBlockingRead`类似,用于表示阻塞式写入操作的异步处理。 + - `impl<'a> Future for WaitBlockingWrite<'a>`: 这是`WaitBlockingWrite`结构体的`Future`实现。它定义了异步操作的返回类型和`poll`方法。在`poll`方法中,根据给定的偏移量,调用文件的`writeat`方法来进行写入操作。如果写入成功,则返回带有写入字节数的`VfsResult`。如果遇到阻塞错误,则返回`Poll::Pending`表示异步操作仍在进行中。如果遇到其他错误,则返回带有错误信息的`VfsResult`。 + +这些结构体和实现提供了异步处理阻塞式读取和写入操作的能力。它们可以在异步上下文中使用,允许在进行阻塞操作时暂停当前任务,并在操作完成后恢复任务的执行。这对于处理文件系统中的阻塞式操作非常有用,以避免阻塞整个应用程序的执行。 + +#### 缓存 + +```rust +pub struct CacheItem { + data: &'static mut [u8], + _trackers: Vec, +} + +static CACHE_TABLE: Mutex> = Mutex::new(BTreeMap::new()); + +/// cached(filename: &str) 判断文件是否被缓存 +/// filename 应包含文件路径,如: 根目录下的 entry-static.exe 为 /entry-static.exe +pub fn cached(filename: &str) -> bool { + CACHE_TABLE.lock().contains_key(filename) +} + +/// cache_read(filename: &str, buffer: &mut [u8], offset: usize) -> usize +/// 从 cache_table 读取文件,需要先使用 cached(filename: &str) 确定文件已经被缓存 +pub fn cache_read(filename: &str, buffer: &mut [u8], offset: usize) -> usize { + let cache_table = CACHE_TABLE.lock(); + let cache_file = cache_table.get(filename).unwrap(); + + let len = buffer.len(); + let rlen = cmp::min(len - offset, buffer.len()); + buffer[..rlen].copy_from_slice(&cache_file.data[offset..offset + rlen]); + rlen +} + +/// cache_file(path: &str) 缓存文件, +#[allow(dead_code)] +pub fn cache_file(path: &str) { + if let Ok(file) = open(path) { + let len = file.metadata().expect("can't get file metadata").size; + let count = ceil_div(len, PAGE_SIZE); + let trackers = frame_alloc_much(count).expect("can't alloc frame trackers from cache"); + let buffer = unsafe { + core::slice::from_raw_parts_mut(trackers[0].0.get_buffer().as_mut_ptr(), len) + }; + let mut cache_item = CacheItem { + data: buffer, + _trackers: trackers, + }; + file.readat(0, &mut cache_item.data) + .expect("can't read file"); + CACHE_TABLE.lock().insert(String::from(path), cache_item); + info!("cache file: {}", path); + } else { + info!("cache file: {} failed", path); + } +} + +/// init() 初始化缓存表 +pub fn init() { + // cache_file("/entry-dynamic.exe"); + // cache_file("/lmbench_all"); +} +``` + +- `pub struct CacheItem`: 这是一个结构体,包含了缓存的数据和用于跟踪缓存帧的`FrameTracker`的向量。 +- `static CACHE_TABLE: Mutex>`: 这是一个静态的互斥锁`Mutex`,用于保护缓存表`BTreeMap`,其中键是文件名,值是对应文件的缓存项。 +- `pub fn cached(filename: &str) -> bool`: 这个函数用于判断文件是否被缓存。它通过获取`CACHE_TABLE`的互斥锁并调用`contains_key`方法来检查缓存表中是否包含指定的文件名。 +- `pub fn cache_read(filename: &str, buffer: &mut [u8], offset: usize) -> usize`: 这个函数用于从缓存表中读取文件数据。它首先获取`CACHE_TABLE`的互斥锁,并根据文件名从缓存表中获取对应的缓存项。然后,根据指定的偏移量和缓冲区的长度,从缓存项的数据中拷贝数据到给定的缓冲区,并返回实际读取的字节数。 +- `pub fn cache_file(path: &str)`: 这个函数用于缓存指定的文件。它首先尝试打开指定路径的文件,然后获取文件的大小,并根据文件大小分配一组`FrameTracker`用于跟踪缓存帧。接下来,它通过`trackers[0]`获取第一个缓存帧的内存地址,并将其转换为可变的字节数组切片。然后,它创建一个`CacheItem`结构体,将缓存的数据和跟踪器存储在其中。接着,它调用文件的`readat`方法将文件数据读取到缓存项的数据中。最后,它将缓存项插入到缓存表中。 +- `pub fn init()`: 这个函数用于初始化缓存表。它可以用来预先缓存一些特定的文件。在当前代码中,它被注释掉了,所以没有实际缓存任何文件。 + +这段代码实现了一个简单的文件缓存系统,它使用互斥锁保护缓存表,提供了判断文件是否被缓存、读取缓存文件和缓存文件的功能。它可以用于减少文件系统的访问延迟,提高文件读取性能。 + +#### dentry + +```rust +pub struct DentryNode { + pub filename: String, + pub node: Arc, + pub parent: Weak, + pub children: Mutex>>, +} + +impl DentryNode { + pub fn new(filename: String, node: Arc, parent: Weak) -> Self { + Self { + filename, + node, + parent, + children: Mutex::new(Vec::new()), + } + } + + /// Mount a fs to DentryTree, return Some if successfully mounted. + /// path: The mounted path. + /// node: fs root directory node. + pub fn mount(path: String, node: Arc) -> Option<()> { + let paths = path.split("/").into_iter(); + let mut dentry = DENTRY_TREE.lock().clone(); + + for x in paths { + dentry = match x { + "." => dentry, + ".." => dentry.parent.upgrade().unwrap_or(dentry), + filename => { + let finded = dentry + .children + .lock() + .iter() + .find(|x| x.filename == *filename) + .cloned(); + match finded { + Some(new_dentry) => new_dentry, + None => dentry + .node + .open(filename, OpenFlags::NONE) + .map_or(None, |x| { + Some(Arc::new(DentryNode::new( + filename.to_string(), + x, + Arc::downgrade(&dentry), + ))) + })?, + } + } + } + } + dentry + .parent + .upgrade() + .unwrap() + .children + .lock() + .push(Arc::new(DentryNode::new( + dentry.filename.clone(), + node, + dentry.parent.clone(), + ))); + Some(()) + } + + pub fn add_child(&mut self, filename: String, node: Arc) { + self.children + .lock() + .push(Arc::new(Self::new(filename, node, Weak::new()))); + } +} + +pub static DENTRY_TREE: LazyInit>> = LazyInit::new(); +``` + +- `pub struct DentryNode`: 这是一个目录项结构体,包含了文件名、节点接口、父目录的弱引用和子目录的互斥锁。 + +- `impl DentryNode`: 这是`DentryNode`结构体的实现。它提供了实例化目录项、挂载文件系统和添加子目录的方法。 + + - `pub fn new(filename: String, node: Arc, parent: Weak) -> Self`: 这个方法用于创建一个新的目录项。它接受文件名、节点接口和父目录的弱引用作为参数,并返回一个`DentryNode`实例。 + - `pub fn mount(path: String, node: Arc) -> Option<()>`: 这个方法用于将文件系统挂载到目录树中。它接受挂载路径和文件系统根目录节点作为参数。它首先根据挂载路径进行路径分割,然后根据路径的不同部分进行相应的处理。如果路径部分为`.`,表示当前目录,不进行任何操作。如果路径部分为`..`,表示上级目录,尝试通过弱引用获取上级目录的节点,如果获取失败,则将当前目录视为上级目录。如果路径部分为文件名,首先在当前目录的子目录中查找是否存在同名的子目录,如果存在,则将查找到的子目录作为新的当前目录。如果不存在同名的子目录,尝试通过当前目录的节点接口打开文件,如果打开成功,则创建一个新的目录项,并将其作为新的当前目录。最后,将文件系统根目录节点添加到当前目录的子目录列表中。 + - `pub fn add_child(&mut self, filename: String, node: Arc)`: 这个方法用于向当前目录添加子目录。它接受子目录的文件名和节点接口作为参数。它通过互斥锁获取子目录列表的可变引用,并将新的子目录项添加到列表中。 + + +#### FAT shim层实现 + +```rust +impl INodeInterface for FatFile { + fn readat(&self, offset: usize, buffer: &mut [u8]) -> VfsResult { + let mut inner = self.inner.lock(); + + if offset >= inner.size { + return Ok(0); + } + let seek_curr = SeekFrom::Start(offset as _); + inner.inner.seek(seek_curr).map_err(as_vfs_err)?; + let len = inner.size; + debug!("off: {:#x} rlen: {:#x}", offset, len); + // read cached file. + inner + .inner + .seek(SeekFrom::Start(offset as u64)) + .map_err(as_vfs_err)?; + let rlen = min(buffer.len(), len as usize - offset); + inner + .inner + .read_exact(&mut buffer[..rlen]) + .map_err(as_vfs_err)?; + Ok(rlen) + } + + fn writeat(&self, offset: usize, buffer: &[u8]) -> VfsResult { + let mut inner = self.inner.lock(); + + // if offset > len + let seek_curr = SeekFrom::Start(offset as _); + let curr_off = inner.inner.seek(seek_curr).map_err(as_vfs_err)? as usize; + if offset != curr_off { + let buffer = vec![0u8; 512]; + loop { + let wlen = cmp::min(offset - inner.size, 512); + + if wlen == 0 { + break; + } + let real_wlen = inner.inner.write(&buffer).map_err(as_vfs_err)?; + inner.size += real_wlen; + } + } + + inner.inner.write_all(buffer).map_err(as_vfs_err)?; + + if offset + buffer.len() > inner.size { + inner.size = offset + buffer.len(); + } + Ok(buffer.len()) + } + + fn flush(&self) -> VfsResult<()> { + self.inner.lock().inner.flush().map_err(as_vfs_err) + } + + fn metadata(&self) -> VfsResult { + let inner = self.inner.lock(); + + Ok(vfscore::Metadata { + filename: &self.filename, + inode: usize::MAX, + file_type: FileType::File, + size: inner.size, + childrens: usize::MAX, + }) + } + + fn truncate(&self, size: usize) -> VfsResult<()> { + self.inner + .lock() + .inner + .seek(SeekFrom::Start(size as u64)) + .map_err(as_vfs_err)?; + self.inner.lock().inner.truncate().map_err(as_vfs_err) + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + stat.ino = 1; // TODO: convert path to number(ino) + stat.mode = StatMode::FILE; // TODO: add access mode + stat.nlink = 1; + stat.uid = 0; + stat.gid = 0; + stat.size = self.metadata().unwrap().size as u64; + stat.blksize = 512; + stat.blocks = self.metadata().unwrap().size as u64 / 512; + stat.rdev = 0; // TODO: add device id + // TODO: add A/M/C time + stat.atime.nsec = 0; + stat.atime.sec = 0; + stat.ctime.nsec = 0; + stat.ctime.sec = 0; + stat.mtime.nsec = 0; + stat.mtime.sec = 0; + Ok(()) + } +} +``` + +这段代码实现了`INodeInterface` trait 对于 `FatFile` 结构体的方法。 + +- `readat(&self, offset: usize, buffer: &mut [u8]) -> VfsResult`: 该方法用于从文件中读取数据。它首先获取内部锁,然后根据给定的偏移量和缓冲区大小,从文件的相应位置读取数据。如果偏移量超过文件大小,则返回0。读取的数据存储在提供的缓冲区中,并返回实际读取的字节数。 +- `writeat(&self, offset: usize, buffer: &[u8]) -> VfsResult`: 该方法用于向文件中写入数据。它首先获取内部锁,然后根据给定的偏移量将文件指针定位到相应位置。如果偏移量与当前文件指针位置不匹配,则在偏移量之前写入空字节。然后将提供的数据写入文件,并根据需要更新文件大小。最后返回写入的字节数。 +- `flush(&self) -> VfsResult<()>`: 该方法用于刷新文件的缓冲区。它获取内部锁,并调用内部文件对象的 `flush` 方法来执行刷新操作。 +- `metadata(&self) -> VfsResult`: 该方法用于获取文件的元数据信息。它获取内部锁,并返回一个包含文件名、文件类型、文件大小等信息的 `Metadata` 结构体。 +- `truncate(&self, size: usize) -> VfsResult<()>`: 该方法用于截断文件到指定的大小。它获取内部锁,并将文件指针定位到给定的大小。然后调用内部文件对象的 `truncate` 方法执行截断操作。 +- `stat(&self, stat: &mut Stat) -> VfsResult<()>`: 该方法用于获取文件的统计信息。它将文件的大小、块大小、块数等信息填充到提供的 `Stat` 结构体中。其他字段如 `ino`、`mode`、`nlink`、`uid`、`gid`、`rdev` 和时间戳等待填充。 + +这些方法实现了 `INodeInterface` trait 中定义的操作,以便与 `FatFile` 类型的文件进行交互。 + +```rust +impl INodeInterface for FatDir { + fn mkdir(&self, name: &str) -> VfsResult> { + self.inner + .create_dir(name) + .map(|dir| -> Arc { + Arc::new(FatDir { + dents_off: Mutex::new(0), + filename: String::from(name), + inner: dir, + }) + }) + .map_err(as_vfs_err) + } + + fn touch(&self, name: &str) -> VfsResult> { + self.inner + .create_file(name) + .map(|file| -> Arc { + Arc::new(FatFile { + filename: String::from(name), + inner: Mutex::new(FatFileInner { + inner: file, + size: 0, + }), + }) + }) + .map_err(as_vfs_err) + } + + fn lookup(&self, _name: &str) -> VfsResult> { + todo!() + } + + fn open(&self, name: &str, _flags: vfscore::OpenFlags) -> VfsResult> { + let file = self + .inner + .iter() + .find(|f| f.as_ref().unwrap().file_name() == name); + let file = file.map(|x| x.unwrap()).ok_or(VfsError::FileNotFound)?; + if file.is_dir() { + Ok(Arc::new(FatDir { + dents_off: Mutex::new(0), + filename: String::from(name), + inner: file.to_dir(), + })) + } else if file.is_file() { + Ok(Arc::new(FatFile { + filename: String::from(name), + inner: Mutex::new(FatFileInner { + inner: file.to_file(), + size: file.len() as usize, + }), + })) + } else { + unreachable!() + } + } + + fn rmdir(&self, name: &str) -> VfsResult<()> { + self.inner.remove(name).map_err(as_vfs_err) + } + + fn remove(&self, name: &str) -> VfsResult<()> { + self.inner.remove(name).map_err(as_vfs_err) + } + + fn read_dir(&self) -> VfsResult> { + Ok(self + .inner + .iter() + .filter_map(|x| { + let x = x.unwrap(); + if x.file_name() == "." || x.file_name() == ".." { + return None; + } + let file_type = { + if x.is_file() { + FileType::File + } else if x.is_dir() { + FileType::Directory + } else { + unreachable!() + } + }; + Some(DirEntry { + filename: x.file_name(), + len: x.len() as usize, + file_type, + }) + }) + .collect()) + } + + fn metadata(&self) -> VfsResult { + Ok(Metadata { + filename: &self.filename, + inode: usize::MAX, + file_type: FileType::Directory, + size: 0, + childrens: self.inner.iter().count(), + }) + } + + fn stat(&self, stat: &mut Stat) -> VfsResult<()> { + stat.ino = 1; // TODO: convert path to number(ino) + stat.mode = StatMode::DIR; // TODO: add access mode + stat.nlink = 1; + stat.uid = 0; + stat.gid = 0; + stat.size = 0; + stat.blksize = 512; + stat.blocks = 0; + stat.rdev = 0; // TODO: add device id + stat.atime.nsec = 0; + stat.atime.sec = 0; + stat.ctime.nsec = 0; + stat.ctime.sec = 0; + stat.mtime.nsec = 0; + stat.mtime.sec = 0; + Ok(()) + } + + fn statfs(&self, statfs: &mut StatFS) -> VfsResult<()> { + statfs.ftype = 32; + statfs.bsize = 512; + statfs.blocks = 80; + statfs.bfree = 40; + statfs.bavail = 0; + statfs.files = 32; + statfs.ffree = 0; + statfs.fsid = 32; + statfs.namelen = 20; + Ok(()) + } + + fn getdents(&self, buffer: &mut [u8]) -> VfsResult { + let buf_ptr = buffer.as_mut_ptr() as usize; + let len = buffer.len(); + let mut ptr: usize = buf_ptr; + let mut finished = 0; + for (i, x) in self.inner.iter().enumerate().skip(*self.dents_off.lock()) { + let x = x.unwrap(); + let filename = x.file_name(); + if filename == "." || filename == ".." { + finished = i + 1; + continue; + } + let filename = filename; + let file_bytes = filename.as_bytes(); + let current_len = ceil_div(size_of::() + file_bytes.len() + 1, 8) * 8; + if len - (ptr - buf_ptr) < current_len { + break; + } + + let dirent: &mut Dirent64 = unsafe { (ptr as *mut Dirent64).as_mut() }.unwrap(); + + dirent.ino = 1; + dirent.off = 0; + // dirent.off = (ptr - buf_ptr) as i64; + dirent.reclen = current_len as u16; + + if x.is_dir() { + dirent.ftype = 4; // DT_DIR + } else { + dirent.ftype = 8; // DT_REF is 8 + } + + let buffer = unsafe { + core::slice::from_raw_parts_mut( + dirent.name.as_mut_ptr(), + current_len - size_of::(), + ) + }; + buffer[..file_bytes.len()].copy_from_slice(file_bytes); + buffer[file_bytes.len()..].fill(0); + + ptr = ptr + current_len; + finished = i + 1; + } + *self.dents_off.lock() = finished; + Ok(ptr - buf_ptr) + } + + fn link(&self, _name: &str, _src: Arc) -> VfsResult<()> { + unimplemented!("unimplemented link in fatfs") + } +} +``` + +这部分代码实现了 `INodeInterface` trait 对于 `FatDir` 结构体的方法。 + +- `mkdir(&self, name: &str) -> VfsResult>`: 该方法用于在目录中创建子目录。它调用内部目录对象的 `create_dir` 方法创建子目录,并返回一个实现了 `INodeInterface` trait 的 `Arc` 包装的 `FatDir` 实例。 +- `touch(&self, name: &str) -> VfsResult>`: 该方法用于在目录中创建文件。它调用内部目录对象的 `create_file` 方法创建文件,并返回一个实现了 `INodeInterface` trait 的 `Arc` 包装的 `FatFile` 实例。 +- `lookup(&self, _name: &str) -> VfsResult>`: 该方法用于查找指定名称的文件或目录。在这个实现中,它暂时没有被实现,而是通过 `todo!()` 宏抛出一个未实现的错误。 +- `open(&self, name: &str, _flags: vfscore::OpenFlags) -> VfsResult>`: 该方法用于打开文件或目录。它通过遍历内部目录对象的条目,找到与给定名称匹配的文件或目录。如果找到的是一个目录,则返回一个实现了 `INodeInterface` trait 的 `Arc` 包装的 `FatDir` 实例。如果找到的是一个文件,则返回一个实现了 `INodeInterface` trait 的 `Arc` 包装的 `FatFile` 实例。 +- `rmdir(&self, name: &str) -> VfsResult<()>`: 该方法用于删除目录。它调用内部目录对象的 `remove` 方法来删除指定名称的目录。 +- `remove(&self, name: &str) -> VfsResult<()>`: 该方法用于删除文件。它调用内部目录对象的 `remove` 方法来删除指定名称的文件。 +- `read_dir(&self) -> VfsResult>`: 该方法用于读取目录的内容。它遍历内部目录对象的条目,并过滤掉 "." 和 ".." 条目。然后根据每个条目的类型(文件或目录),构建一个 `DirEntry` 结构体,并将所有条目收集到一个 `Vec` 中返回。 +- `metadata(&self) -> VfsResult`: 该方法用于获取目录的元数据信息。它返回一个包含目录名称、类型(目录)、大小和子目录/文件数量等信息的 `Metadata` 结构体。 +- `stat(&self, stat: &mut Stat) -> VfsResult<()>`: 该方法用于获取目录的统计信息。它将目录的大小、块大小、块数等信息填充到提供的 `Stat` 结构体中。其他字段如 `ino`、`mode`、`nlink`、`uid`、`gid`、`rdev` 和时间戳等待填充。 +- `statfs(&self, statfs: &mut StatFS) -> VfsResult<()>`: 该方法用于获取文件系统的统计信息。它将文件系统类型、块大小、总块数、空闲块数、可用块数、文件数、空闲文件数、文件系统 ID 和最大文件名长度等信息填充到提供的 `StatFS` 结构体中。 +- `getdents(&self, buffer: &mut [u8]) -> VfsResult`: 该方法用于获取目录的目录项(文件和子目录)。它遍历内部目录对象的条目,并将每个条目的信息填充到提供的缓冲区中,使用 `Dirent64` 结构体进行目录项的描述。每个目录项的长度可能不同,因此需要根据 `Dirent64` 结构体的大小进行对齐。同时,该方法还维护了一个偏移量,以便在下一次调用该方法时返回正确的目录项。 + +这些方法实现了 `INodeInterface` trait,使得 `FatDir` 结构体能够作为一个目录节点在文件系统中使用。它们提供了对目录的创建、查找、打开、删除、读取内容以及获取元数据和统计信息的功能。 + +#### 管道 + +```rust +pub struct PipeSender(Arc>>); + +impl INodeInterface for PipeSender { + fn writeat(&self, _offset: usize, buffer: &[u8]) -> VfsResult { + let mut queue = self.0.lock(); + if queue.len() > 0x50000 { + Err(vfscore::VfsError::Blocking) + } else { + let wlen = buffer.len(); + queue.extend(buffer.iter()); + Ok(wlen) + } + } + + fn poll(&self, events: PollEvent) -> VfsResult { + let mut res = PollEvent::NONE; + if events.contains(PollEvent::POLLOUT) { + if self.0.lock().len() <= 0x50000 { + res |= PollEvent::POLLOUT; + } + } + Ok(res) + } +} + +// pipe reader, just can read. +pub struct PipeReceiver { + queue: Arc>>, + sender: Weak, +} + +impl INodeInterface for PipeReceiver { + fn readat(&self, _offset: usize, buffer: &mut [u8]) -> VfsResult { + let mut queue = self.queue.lock(); + let rlen = cmp::min(queue.len(), buffer.len()); + queue + .drain(..rlen) + .enumerate() + .into_iter() + .for_each(|(i, x)| { + buffer[i] = x; + }); + if rlen == 0 && Weak::strong_count(&self.sender) > 0 { + Err(vfscore::VfsError::Blocking) + } else { + Ok(rlen) + } + } + + fn poll(&self, events: PollEvent) -> VfsResult { + let mut res = PollEvent::NONE; + if events.contains(PollEvent::POLLIN) { + if self.queue.lock().len() > 0 { + res |= PollEvent::POLLIN; + } else if Weak::strong_count(&self.sender) == 0 { + res |= PollEvent::POLLERR; + } + } + if events.contains(PollEvent::POLLERR) { + if self.queue.lock().len() == 0 && Weak::strong_count(&self.sender) == 0 { + res |= PollEvent::POLLERR; + } + } + Ok(res) + } +} + +pub fn create_pipe() -> (Arc, Arc) { + let queue = Arc::new(Mutex::new(VecDeque::new())); + let sender = Arc::new(PipeSender(queue.clone())); + ( + Arc::new(PipeReceiver { + queue: queue.clone(), + sender: Arc::downgrade(&sender), + }), + sender, + ) +} + +``` + +这段代码实现了一个管道(pipe)的设计,其中包括了管道发送端(`PipeSender`)和管道接收端(`PipeReceiver`)。 + +`PipeSender` 结构体实现了 `INodeInterface` trait,用于管道的写操作。具体实现如下: + +- `writeat(&self, _offset: usize, buffer: &[u8]) -> VfsResult`:该方法用于在管道中写入数据。它首先获取管道队列的锁,检查队列的长度是否超过了限制(0x50000)。如果超过了限制,则返回一个 `VfsError::Blocking` 错误,表示写操作被阻塞。否则,将数据写入队列,并返回写入的字节数。 +- `poll(&self, events: PollEvent) -> VfsResult`:该方法用于轮询管道的事件。在这个实现中,只处理 `POLLOUT` 事件。如果队列的长度小于等于限制(0x50000),则设置 `res` 变量的值为 `POLLOUT`,表示可写。最后返回 `res`。 + +`PipeReceiver` 结构体也实现了 `INodeInterface` trait,用于管道的读操作。具体实现如下: + +- `readat(&self, _offset: usize, buffer: &mut [u8]) -> VfsResult`:该方法用于从管道中读取数据。它首先获取管道队列的锁,计算要读取的字节数(取队列长度和缓冲区长度的最小值),然后通过 `drain` 方法从队列中取出数据,并将其填充到缓冲区中。如果读取的字节数为零,并且发送端的引用计数大于零(即发送端仍然存在),则返回一个 `VfsError::Blocking` 错误,表示读操作被阻塞。否则,返回读取的字节数。 +- `poll(&self, events: PollEvent) -> VfsResult`:该方法用于轮询管道的事件。在这个实现中,处理 `POLLIN` 和 `POLLERR` 事件。如果队列的长度大于零,则设置 `res` 变量的值为 `POLLIN`,表示可读。如果队列的长度为零,并且发送端的引用计数为零,则设置 `res` 变量的值为 `POLLERR`,表示发生错误。最后返回 `res`。 + +`create_pipe` 函数用于创建一个管道,返回一个包含管道接收端和管道发送端的元组。它首先创建一个共享队列 `queue`,然后使用 `Arc` 包装并克隆了该队列,分别作为管道接收端和管道发送端的字段。管道发送端的 `Arc` 包装对象被弱引用为 `sender`,用于在管道接收端中判断发送端是否还存在。最后将管道接收端和管道发送端作为元组返回。 + +#### 设计亮点 + +1. **挂载功能**:该文件系统设计实现了挂载和卸载功能,允许将不同的文件系统挂载到指定的路径上。通过 `mount` 函数可以将文件系统与路径关联起来,并使用 `umount` 函数进行卸载。这使得文件系统具有灵活的扩展性和可定制性,可以根据需求挂载不同的文件系统,并在运行时进行动态管理。 +2. **路径处理**:文件系统对路径进行了灵活的处理和重建。在 `rebuild_path` 函数中,路径的每个组件被逐级处理,忽略空字符串和`.`,并根据`..`移除上一级组件。这样可以确保路径的规范化和正确性,避免了路径中的冗余和错误。 +3. **多文件系统支持**:通过使用 `MOUNTS` 集合,文件系统设计支持同时挂载多个文件系统,并根据给定的路径选择正确的文件系统进行操作。在 `open` 函数中,它遍历挂载路径集合,并根据路径匹配的规则选择正确的文件系统进行操作。这种设计允许不同的文件系统共存,并根据路径来区分和访问它们。 +4. **并发安全**:通过使用 `Mutex` 互斥锁,文件系统设计保证了对 `MOUNTS` 集合的并发访问的安全性。在进行挂载和卸载操作时,通过获取互斥锁的独占访问权限,避免了并发访问导致的数据不一致和竞态条件。 \ No newline at end of file diff --git "a/docs/\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md" "b/docs/\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md" new file mode 100644 index 00000000..cb7fa95d --- /dev/null +++ "b/docs/\346\250\241\345\235\227\345\214\226\350\256\276\350\256\241.md" @@ -0,0 +1,9 @@ +# 模块化设计 + +## cfg 设计 +cfg to qemu + +如果有一个 cfg 在 RUSTFLAGS 中叫做 board 那么必定存在一个 ENV 叫做 CARGO_CFG_BOARD。 + +[链接](https://doc.rust-lang.org/cargo/reference/environment-variables.html) + diff --git "a/docs/\350\231\232\346\213\237\346\226\207\344\273\266\347\263\273\347\273\237.md" "b/docs/\350\231\232\346\213\237\346\226\207\344\273\266\347\263\273\347\273\237.md" new file mode 100644 index 00000000..e0b564de --- /dev/null +++ "b/docs/\350\231\232\346\213\237\346\226\207\344\273\266\347\263\273\347\273\237.md" @@ -0,0 +1,477 @@ +# 虚拟文件系统 + +虚拟文件系统的设计如下 + +```rust +bitflags::bitflags! { + #[derive(Debug, Clone)] + pub struct OpenFlags: usize { + // reserve 3 bits for the access mode + const NONE = 0; + const O_RDONLY = 0; + const O_WRONLY = 1; + const O_RDWR = 2; + const O_ACCMODE = 3; + const O_CREAT = 0o100; + const O_EXCL = 0o200; + const O_NOCTTY = 0o400; + const O_TRUNC = 0o1000; + const O_APPEND = 0o2000; + const O_NONBLOCK = 0o4000; + const O_DSYNC = 0o10000; + const O_SYNC = 0o4010000; + const O_RSYNC = 0o4010000; + const O_DIRECTORY = 0o200000; + const O_NOFOLLOW = 0o400000; + const O_CLOEXEC = 0o2000000; + + const O_ASYNC = 0o20000; + const O_DIRECT = 0o40000; + const O_LARGEFILE = 0o100000; + const O_NOATIME = 0o1000000; + const O_PATH = 0o10000000; + const O_TMPFILE = 0o20200000; + } +} + +bitflags::bitflags! { + pub struct MMapFlags: usize { + const MAP_PRIVATE = 0x1; + const MAP_SHARED = 0x2; + const MAP_FIXED = 0x4; + const MAP_ANONYOMUS = 0x8; + } + + #[derive(Debug)] + pub struct StatMode: u32 { + const NULL = 0; + /// Type + const TYPE_MASK = 0o170000; + /// FIFO + const FIFO = 0o010000; + /// character device + const CHAR = 0o020000; + /// directory + const DIR = 0o040000; + /// block device + const BLOCK = 0o060000; + /// ordinary regular file + const FILE = 0o100000; + /// symbolic link + const LINK = 0o120000; + /// socket + const SOCKET = 0o140000; + + /// Set-user-ID on execution. + const SET_UID = 0o4000; + /// Set-group-ID on execution. + const SET_GID = 0o2000; + + /// Read, write, execute/search by owner. + const OWNER_MASK = 0o700; + /// Read permission, owner. + const OWNER_READ = 0o400; + /// Write permission, owner. + const OWNER_WRITE = 0o200; + /// Execute/search permission, owner. + const OWNER_EXEC = 0o100; + + /// Read, write, execute/search by group. + const GROUP_MASK = 0o70; + /// Read permission, group. + const GROUP_READ = 0o40; + /// Write permission, group. + const GROUP_WRITE = 0o20; + /// Execute/search permission, group. + const GROUP_EXEC = 0o10; + + /// Read, write, execute/search by others. + const OTHER_MASK = 0o7; + /// Read permission, others. + const OTHER_READ = 0o4; + /// Write permission, others. + const OTHER_WRITE = 0o2; + /// Execute/search permission, others. + const OTHER_EXEC = 0o1; + } + + #[derive(Debug, Clone, PartialEq)] + pub struct PollEvent: u16 { + const NONE = 0; + const POLLIN = 0x001; + const POLLPRI = 0x002; + const POLLOUT = 0x004; + const POLLRDNORM = 0x040; + const POLLRDBAND = 0x080; + const POLLWRNORM = 0x100; + const POLLWRBAND = 0x200; + const POLLMSG = 0x400; + const POLLREMOVE = 0x1000; + const POLLRDHUP = 0x2000; + const POLLERR = 0x008; + const POLLHUP = 0x010; + const POLLNVAL = 0x020; + } +} +``` + +1. `OpenFlags` 结构体表示文件打开标志。它定义了一系列常量成员,用于设置文件的打开方式和访问权限,如只读、只写、读写等。每个常量都是一个位标志,可以通过按位或操作进行组合使用。 +2. `MMapFlags` 结构体表示内存映射标志。它定义了一组常量成员,用于设置内存映射的选项,如私有映射、共享映射、固定映射等。这些常量可以通过按位或操作进行组合使用。 +3. `StatMode` 结构体表示文件状态模式。它定义了一组常量成员,用于表示文件的类型、权限和属性。例如,文件类型可以是普通文件、目录、符号链接等。权限部分定义了文件所有者、组和其他用户的读取、写入和执行权限。这些常量可以通过按位与操作进行检查。 +4. `PollEvent` 结构体表示轮询事件。它定义了一组常量成员,用于表示在事件轮询过程中不同的事件类型,如可读、可写、错误等。这些常量可以通过按位与操作进行检查。 + +这些标志位集合的定义使用了 Rust 的 `bitflags` 宏,它使得在虚拟文件系统中表示和操作不同的选项和状态更加方便和直观。通过使用这些标志位集合,可以更灵活地控制和管理虚拟文件系统的行为和属性。 + +```rust +pub const UTIME_NOW: usize = 0x3fffffff; +pub const UTIME_OMIT: usize = 0x3ffffffe; + +#[derive(Debug, Clone, Copy)] +pub enum VfsError { + NotLinkFile, + NotDir, + NotFile, + NotSupported, + FileNotFound, + AlreadyExists, + InvalidData, + DirectoryNotEmpty, + InvalidInput, + StorageFull, + UnexpectedEof, + WriteZero, + Io, + Blocking, + NoMountedPoint, + NotAPipe, + NotWriteable, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum FileType { + File, + Directory, + Device, + Socket, + Link, +} + +#[derive(Debug, Copy, Clone)] +pub enum SeekFrom { + SET(usize), + CURRENT(isize), + END(isize), +} + +#[derive(Debug, Clone)] +pub struct Metadata<'a> { + pub filename: &'a str, + pub inode: usize, + pub file_type: FileType, + pub size: usize, + pub childrens: usize, +} + +pub struct DirEntry { + pub filename: String, + pub len: usize, + pub file_type: FileType, +} + +pub trait FileSystem: Send + Sync { + fn root_dir(&'static self) -> Arc; + fn name(&self) -> &str; + fn flush(&self) -> VfsResult<()> { + Err(VfsError::FileNotFound) + } +} +``` + +1. `pub const UTIME_NOW: usize = 0x3fffffff;` 和 `pub const UTIME_OMIT: usize = 0x3ffffffe;` 是关于文件时间的常量定义。它们用于表示不同的时间选项,用于更新文件的访问时间和修改时间。 + +2. `VfsError` 枚举表示虚拟文件系统可能出现的错误类型。它列举了多种错误,如不是链接文件、不是目录、不是文件等。每个错误类型都是独立的枚举成员,用于标识不同的错误情况。 + +3. `FileType` 枚举表示文件的类型。它定义了几种文件类型,包括文件、目录、设备、套接字和链接。每个文件类型都是独立的枚举成员,用于标识不同类型的文件。 + +4. `SeekFrom` 枚举表示文件偏移量的起始位置。它定义了三种不同的偏移量位置:从文件开头开始的偏移量、从当前位置开始的偏移量和从文件末尾开始的偏移量。每个起始位置都有对应的参数值。 + +5. `Metadata` 结构体表示文件的元数据信息。它包含文件名、inode 号、文件类型、大小和子文件数等属性。这些属性用于描述文件的基本信息。 + +6. 这部分代码是 INodeInterface trait 的默认实现。它提供了一组默认的方法实现,这些方法返回了一个 VfsError::NotSupported 或 VfsError::NotDir 或 VfsError::NotFile 错误,表示对于该具体的文件节点类型,该操作不被支持或不适用。 + + 下面是这些默认方法的解释: + + metadata(&self) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持获取文件节点的元数据信息。 + + readat(&self, _offset: usize, _buffer: &mut [u8]) -> VfsResult: 返回 VfsError::NotFile 错误,表示当前节点不是文件,不支持读取操作。 + + writeat(&self, _offset: usize, _buffer: &[u8]) -> VfsResult: 返回 VfsError::NotFile 错误,表示当前节点不是文件,不支持写入操作。 + + mkdir(&self, _name: &str) -> VfsResult>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持创建子目录。 + + rmdir(&self, _name: &str) -> VfsResult<()>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持删除子目录。 + + remove(&self, _name: &str) -> VfsResult<()>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持删除文件。 + + touch(&self, _name: &str) -> VfsResult>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持创建文件。 + + read_dir(&self) -> VfsResult>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持读取目录信息。 + + lookup(&self, _name: &str) -> VfsResult>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持查找子节点。 + + open(&self, _name: &str, _flags: OpenFlags) -> VfsResult>: 返回 VfsError::NotDir 错误,表示当前节点不是目录,不支持打开文件。 + + ioctl(&self, _command: usize, _arg: usize) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持 ioctl 操作。 + + truncate(&self, _size: usize) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持截断文件操作。 + + flush(&self) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持刷新操作。 + + resolve_link(&self) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持解析链接。 + + link(&self, _name: &str, _src: Arc) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持创建链接。 + + unlink(&self, _name: &str) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持删除链接。 + + mmap(&self, _offset: usize, _size: usize, _flags: MMapFlags) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持内存映射操作。 + + stat(&self, _stat: &mut Stat) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持获取文件节点的状态信息。 + + mount(&self, _path: &str) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持挂载操作。 + + umount(&self) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持卸载操作。 + + statfs(&self, _statfs:&mut StatFS) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持获取文件系统的状态信息。 + + getdents(&self, _buffer: &mut [u8]) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持读取目录项操作。 + + utimes(&self, _times: &mut [TimeSpec]) -> VfsResult<()>: 返回 VfsError::NotSupported 错误,表示不支持修改文件的访问和修改时间。 + + poll(&self, _events: PollEvent) -> VfsResult: 返回 VfsError::NotSupported 错误,表示不支持轮询操作。 + + 最后的 impl_downcast!(sync INodeInterface) 宏用于为 INodeInterface trait 实现 DowncastSync 特性,以支持类型转换。 + +7. `DirEntry` 结构体表示目录中的条目。它包含了文件名、长度和文件类型等属性,用于描述目录中的每个文件或子目录。 + +8. `FileSystem` 是一个 trait,定义了虚拟文件系统的基本操作。它包含了获取根目录、获取文件系统名称和刷新操作等方法。实现该 trait 的类型应该能够提供文件系统的基本功能。 + +这部分代码定义了虚拟文件系统中使用的常量、枚举和结构体,用于表示文件系统的不同属性、类型、错误和操作。这些定义提供了一种抽象的方式来操作和管理虚拟文件系统的文件和目录。 + +```rust +pub type VfsResult = core::result::Result; + +#[repr(C)] +#[derive(Default, Clone, Copy, Debug)] +pub struct TimeSpec { + pub sec: usize, /* 秒 */ + pub nsec: usize, /* 纳秒, 范围在0~999999999 */ +} + +impl TimeSpec { + pub fn to_nsec(&self) -> usize { + self.sec * 1_000_000_000 + self.nsec + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct Stat { + pub dev: u64, // 设备号 + pub ino: u64, // inode + pub mode: StatMode, // 设备mode + pub nlink: u32, // 文件links + pub uid: u32, // 文件uid + pub gid: u32, // 文件gid + pub rdev: u64, // 文件rdev + pub __pad: u64, // 保留 + pub size: u64, // 文件大小 + pub blksize: u32, // 占用块大小 + pub __pad2: u32, // 保留 + pub blocks: u64, // 占用块数量 + pub atime: TimeSpec, // 最后访问时间 + pub mtime: TimeSpec, // 最后修改时间 + pub ctime: TimeSpec, // 最后创建时间 +} + +#[repr(C)] +pub struct StatFS { + pub ftype: u64, // 文件系统的类型 + pub bsize: u64, // 经优化后的传输块的大小 + pub blocks: u64, // 文件系统数据块总数 + pub bfree: u64, // 可用块数 + pub bavail: u64, // 普通用户能够获得的块数 + pub files: u64, // 文件结点总数 + pub ffree: u64, // 可用文件结点数 + pub fsid: u64, // 文件系统标识 + pub namelen: u64, // 文件名的最大长度 +} + +#[repr(C)] +pub struct Dirent64 { + pub ino: u64, // 索引结点号 + pub off: i64, // 到下一个dirent的偏移 + pub reclen: u16, // 当前dirent的长度 + pub ftype: u8, // 文件类型 + pub name: [u8; 0], // 文件名 +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct PollFd { + pub fd: u32, + pub events: PollEvent, + pub revents: PollEvent, +} +``` + +1. `pub type VfsResult = core::result::Result;` 定义了一个类型别名 `VfsResult`,它是一个结果类型,可以返回一个值 `T` 或一个 `VfsError` 错误。这样可以在文件系统操作中统一处理成功和失败的情况。 +2. `TimeSpec` 结构体表示时间的规范。它包含了秒和纳秒两个字段,用于表示时间的精确值。`to_nsec` 方法将秒和纳秒转换为纳秒的总数。 +3. `Stat` 结构体表示文件的状态信息。它包含了多个字段,如设备号、inode 号、文件的访问权限、链接数、用户和组 ID、文件大小、占用块数量以及最后访问、修改和创建时间等。 +4. `StatFS` 结构体表示文件系统的状态信息。它包含了文件系统的类型、经优化后的传输块大小、数据块总数、可用块数、普通用户可获得的块数、文件节点总数、可用文件节点数、文件系统标识和文件名的最大长度等。 +5. `Dirent64` 结构体表示目录中的一个条目。它包含了索引节点号、到下一个条目的偏移、当前条目的长度、文件类型和文件名等。 +6. `PollFd` 结构体表示轮询文件描述符的信息。它包含了文件描述符、待轮询的事件类型和返回的事件类型等。 + +这些结构体定义了不同层面上的文件和文件系统的信息和属性,用于在虚拟文件系统中描述和操作文件、目录和文件系统的状态。 + +```rust +pub trait INodeInterface: DowncastSync + Send + Sync { + fn metadata(&self) -> VfsResult { + Err(VfsError::NotSupported) + } + + fn readat(&self, _offset: usize, _buffer: &mut [u8]) -> VfsResult { + Err(VfsError::NotFile) + } + + fn writeat(&self, _offset: usize, _buffer: &[u8]) -> VfsResult { + Err(VfsError::NotFile) + } + + fn mkdir(&self, _name: &str) -> VfsResult> { + Err(VfsError::NotDir) + } + + fn rmdir(&self, _name: &str) -> VfsResult<()> { + Err(VfsError::NotDir) + } + + fn remove(&self, _name: &str) -> VfsResult<()> { + Err(VfsError::NotDir) + } + + fn touch(&self, _name: &str) -> VfsResult> { + Err(VfsError::NotDir) + } + + fn read_dir(&self) -> VfsResult> { + Err(VfsError::NotDir) + } + + fn lookup(&self, _name: &str) -> VfsResult> { + Err(VfsError::NotDir) + } + + fn open(&self, _name: &str, _flags: OpenFlags) -> VfsResult> { + Err(VfsError::NotDir) + } + + fn ioctl(&self, _command: usize, _arg: usize) -> VfsResult { + Err(VfsError::NotSupported) + } + + fn truncate(&self, _size: usize) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn flush(&self) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn resolve_link(&self) -> VfsResult { + Err(VfsError::NotSupported) + } + + fn link(&self, _name: &str, _src: Arc) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn unlink(&self, _name: &str) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn mmap(&self, _offset: usize, _size: usize, _flags: MMapFlags) -> VfsResult { + Err(VfsError::NotSupported) + } + + fn stat(&self, _stat: &mut Stat) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn mount(&self, _path: &str) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn umount(&self) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn statfs(&self, _statfs: &mut StatFS) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn getdents(&self, _buffer: &mut [u8]) -> VfsResult { + Err(VfsError::NotSupported) + } + + fn utimes(&self, _times: &mut [TimeSpec]) -> VfsResult<()> { + Err(VfsError::NotSupported) + } + + fn poll(&self, _events: PollEvent) -> VfsResult { + Err(VfsError::NotSupported) + } +} + +impl_downcast!(sync INodeInterface); +``` + +这部分代码是 `INodeInterface` trait 的默认实现。它提供了一组默认的方法实现,这些方法返回了一个 `VfsError::NotSupported` 或 `VfsError::NotDir` 或 `VfsError::NotFile` 错误,表示对于该具体的文件节点类型,该操作不被支持或不适用。 + +下面是这些默认方法的解释: + +- `metadata(&self) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持获取文件节点的元数据信息。 +- `readat(&self, _offset: usize, _buffer: &mut [u8]) -> VfsResult`: 返回 `VfsError::NotFile` 错误,表示当前节点不是文件,不支持读取操作。 +- `writeat(&self, _offset: usize, _buffer: &[u8]) -> VfsResult`: 返回 `VfsError::NotFile` 错误,表示当前节点不是文件,不支持写入操作。 +- `mkdir(&self, _name: &str) -> VfsResult>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持创建子目录。 +- `rmdir(&self, _name: &str) -> VfsResult<()>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持删除子目录。 +- `remove(&self, _name: &str) -> VfsResult<()>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持删除文件。 +- `touch(&self, _name: &str) -> VfsResult>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持创建文件。 +- `read_dir(&self) -> VfsResult>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持读取目录信息。 +- `lookup(&self, _name: &str) -> VfsResult>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持查找子节点。 +- `open(&self, _name: &str, _flags: OpenFlags) -> VfsResult>`: 返回 `VfsError::NotDir` 错误,表示当前节点不是目录,不支持打开文件。 +- `ioctl(&self, _command: usize, _arg: usize) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持 ioctl 操作。 +- `truncate(&self, _size: usize) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持截断文件操作。 +- `flush(&self) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持刷新操作。 +- `resolve_link(&self) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持解析链接。 +- `link(&self, _name: &str, _src: Arc) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持创建链接。 +- `unlink(&self, _name: &str) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持删除链接。 +- `mmap(&self, _offset: usize, _size: usize, _flags: MMapFlags) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持内存映射操作。 +- `stat(&self, _stat: &mut Stat) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持获取文件节点的状态信息。 +- `mount(&self, _path: &str) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持挂载操作。 +- `umount(&self) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持卸载操作。 +- `statfs(&self, _statfs:&mut StatFS) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持获取文件系统的状态信息。 +- `getdents(&self, _buffer: &mut [u8]) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持读取目录项操作。 +- `utimes(&self, _times: &mut [TimeSpec]) -> VfsResult<()>`: 返回 `VfsError::NotSupported` 错误,表示不支持修改文件的访问和修改时间。 +- `poll(&self, _events: PollEvent) -> VfsResult`: 返回 `VfsError::NotSupported` 错误,表示不支持轮询操作。 + +最后的 `impl_downcast!(sync INodeInterface)` 宏用于为 `INodeInterface` trait 实现 DowncastSync 特性,以支持类型转换。 + +设计亮点 + +1. 接口抽象化:使用 `pub trait INodeInterface` 定义了文件节点的接口,通过定义一组方法来表示文件和目录的常见操作。这种接口抽象化的设计使得文件系统可以支持不同类型的文件节点,并能够以统一的方式进行操作。 +2. 异常处理机制:使用 `VfsResult` 类型作为方法的返回值,通过 `Err` 返回不支持的操作错误。这种异常处理机制使得用户可以根据返回的错误类型来判断操作是否被支持,从而避免在不支持的操作上浪费时间和资源。 +3. Trait 对象的使用:使用 `Arc` 作为方法的返回值类型,通过 trait 对象的方式,实现了对不同类型文件节点的统一处理。这种设计允许不同类型的文件节点具有不同的实现,同时又能够通过 trait 对象来进行通用的操作。 +4. 默认方法实现:虚拟文件系统为 `INodeInterface` 提供了一组默认的方法实现,这些方法在默认情况下返回了不支持操作的错误。这样的设计使得具体的文件节点类型可以选择性地重写这些方法,以实现自定义的行为。 +5. Downcast 支持:通过 `impl_downcast!(sync INodeInterface)` 宏对 `INodeInterface` 实现了 `DowncastSync` 特性,使得类型转换更加方便。这样,用户可以在需要时将 trait 对象转换回具体的文件节点类型,以访问特定类型的方法和属性。 + +这些设计亮点使得虚拟文件系统具有灵活性、可扩展性和易用性,能够适应不同类型的文件节点,并提供统一的操作接口。 \ No newline at end of file diff --git "a/docs/\351\223\276\346\216\245\350\204\232\346\234\254.md" "b/docs/\351\223\276\346\216\245\350\204\232\346\234\254.md" new file mode 100644 index 00000000..9c1267a3 --- /dev/null +++ "b/docs/\351\223\276\346\216\245\350\204\232\346\234\254.md" @@ -0,0 +1,125 @@ +# 连接脚本 + +刚开始的连接脚本为了实现高半核,参考了一下 `rcore`,但是后来在使用的过程中发现参考 `rcore` 的脚本并不能完美的解决我们的问题,刚开始我们的映射地址如下: + +```plain +0xffffffff_c0000000 -> 0x80000000 (1G) +``` + +后来我们开始修改自己的连接脚本和映射地址以及启动代码,启动代码如下: + +```rust +const STACK_SIZE: usize = 0x10000; + +#[link_section = ".bss.stack"] +static mut STACK: [u8; STACK_SIZE] = [0u8; STACK_SIZE]; + +#[link_section = ".data.prepage"] +static mut PAGE_TABLE: [PTE; PAGE_ITEM_COUNT] = { + let mut arr: [PTE; PAGE_ITEM_COUNT] = [PTE::new(); PAGE_ITEM_COUNT]; + // 初始化页表信息 + // 0x00000000_80000000 -> 0x80000000 (1G) + // 高半核 + // 0xffffffc0_00000000 -> 0x00000000 (1G) + // 0xffffffc0_80000000 -> 0x80000000 (1G) + arr[2] = PTE::from_addr(0x8000_0000, PTEFlags::VRWX); + arr[0x100] = PTE::from_addr(0x0, PTEFlags::GVRWX); + arr[0x102] = PTE::from_addr(0x8000_0000, PTEFlags::GVRWX); + arr +}; + +core::arch::asm!( + // 1. 设置栈信息 + // sp = bootstack + (hartid + 1) * 0x10000 + " + la sp, {boot_stack} + li t0, {stack_size} + add sp, sp, t0 // set boot stack + + li s0, {virt_addr_start} // add virtual address + add sp, sp, s0 + ", + // 2. 开启分页模式 + // satp = (8 << 60) | PPN(page_table) + " + la t0, {page_table} + srli t0, t0, 12 + li t1, 8 << 60 + or t0, t0, t1 + csrw satp, t0 + sfence.vma + ", + // 3. 跳到 rust_main 函数,绝对路径 + " + la a2, rust_main + add a2, a2, s0 + jalr a2 // call rust_main + ", + stack_size = const STACK_SIZE, + boot_stack = sym STACK, + page_table = sym PAGE_TABLE, + virt_addr_start = const VIRT_ADDR_START, + options(noreturn), +) +``` + +但是在设置链接脚本的过程中也产生了一些问题,就是我们发现设置后 `page_table` 并不是 `4k` 对齐的,在连接脚本内设置的 `. = ALIGN(4K)` 是对 `VMA` 进行对齐,而不是 `LMA(L 指 Load)`,因此我们开始寻找新的解决方案,发现在 `section` 后直接跟 `4K` 可以解决这个问题。因此我们的链接脚本改为如下: + +```ld +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0xffffffc080200000; + +__ENTRY_ADDR = 0x80200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text ALIGN(4K): AT(__ENTRY_ADDR) { + stext = .; + *(.text.entry) + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata ALIGN(4K): { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data ALIGN(4K): { + . = ALIGN(4K); + *(.data.prepage) + . = ALIGN(4K); + sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + *(.bss.stack) + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + ebss = .; + } + + PROVIDE(end = .); +} +``` + +# 下一步 + +然后我们就可以把下面的地址分配给堆和栈,从而动态的分配内存。目前还需要考虑的问题是,如果堆由于满了再去申请内存导致堆移除,这个时候进行缺页映射会不会再去堆上申请数据?如果申请数据的话大概率还是报错,所以应该怎么解决这个问题? diff --git "a/docs/\351\241\265\345\270\247\345\210\206\351\205\215\345\231\250.md" "b/docs/\351\241\265\345\270\247\345\210\206\351\205\215\345\231\250.md" new file mode 100644 index 00000000..559a066c --- /dev/null +++ "b/docs/\351\241\265\345\270\247\345\210\206\351\205\215\345\231\250.md" @@ -0,0 +1,803 @@ +# 页帧分配器 + +页帧分配器(Page Frame Allocator)是操作系统中的一部分,用于管理物理内存中的页帧(Page Frame),以供操作系统和应用程序使用。 + +在虚拟内存系统中,物理内存被划分为固定大小的页帧(通常是4KB)。页帧分配器的主要任务是跟踪哪些页帧已被分配,并提供分配和释放页帧的功能。 + +页帧分配器通常维护一个数据结构,例如位图或空闲链表,来记录和管理可用的页帧。当应用程序或操作系统需要分配内存时,页帧分配器会查找空闲的页帧并标记为已分配。当内存不再需要时,页帧分配器将释放已使用的页帧,使其变为可用状态。 + +## 主要设计 + +```rust +#![no_std] + +#[macro_use] +extern crate alloc; + +use core::mem::size_of; + +use alloc::vec::Vec; +use arch::{PhysPage, PAGE_SIZE, VIRT_ADDR_START}; +use bit_field::{BitArray, BitField}; +use kheader::mm::get_memorys; +use log::info; +use sync::Mutex; + +pub const fn floor(a: usize, b: usize) -> usize { + return (a + b - 1) / b; +} + +pub const fn ceil_div(a: usize, b: usize) -> usize { + return (a + b - 1) / b; +} + +#[derive(Debug)] +/// 页帧 +/// +/// 用这个代表一个已经被分配的页表,并且利用 Drop 机制保证页表能够顺利被回收 +pub struct FrameTracker(pub PhysPage); + +impl FrameTracker { + pub fn new(ppn: PhysPage) -> Self { + Self(ppn) + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + self.0.drop_clear(); + FRAME_ALLOCATOR.lock().dealloc(self.0); + } +} + +/// 页帧分布图 +/// +/// 利用页帧分布图保存页帧分配器中的空闲内存,并且利用 bitArray 记录页帧使用情况 +pub struct FrameRegionMap { + bits: Vec, + ppn: PhysPage, + ppn_end: PhysPage, +} + +impl FrameRegionMap { + /// 创建页帧分布图 + /// + /// start_addr: usize 空闲页帧起始地址 + /// end_addr: usize 空闲页帧结束地址 + #[inline] + pub fn new(start_addr: usize, end_addr: usize) -> Self { + let mut bits = vec![0usize; floor((end_addr - start_addr) / PAGE_SIZE, 64)]; + + // set non-exists memory bit as 1 + for i in (end_addr - start_addr) / PAGE_SIZE..bits.len() * 64 { + bits.set_bit(i, true); + } + + Self { + bits, + ppn: PhysPage::from_addr(start_addr), + ppn_end: PhysPage::from_addr(end_addr), + } + } + + /// 获取页帧分布图中没有使用的页帧数量 + #[inline] + pub fn get_free_page_count(&self) -> usize { + self.bits.iter().fold(0, |mut sum, x| { + if *x == 0 { + sum + 64 + } else { + for i in 0..64 { + sum += match (*x).get_bit(i) { + true => 0, + false => 1, + }; + } + sum + } + }) + } + + /// 在 `bitArray` 指定位置获取一个空闲的页 + /// + /// index: usize 指定的位置 self.bits[index] + #[inline] + fn alloc_in_pos(&mut self, index: usize) -> Option { + for bit_index in 0..64 { + if !self.bits[index].get_bit(bit_index) { + self.bits[index].set_bit(bit_index, true); + return Some(FrameTracker::new(self.ppn + index * 64 + bit_index)); + } + } + None + } + + /// 申请一个空闲页 + #[inline] + pub fn alloc(&mut self) -> Option { + for i in 0..self.bits.len() { + if self.bits[i] != usize::MAX { + return self.alloc_in_pos(i); + } + } + None + } + + /// 申请多个空闲页, 空闲页是连续的 + /// + /// pages: usize 要申请的页表数量 + #[allow(unused_assignments)] + pub fn alloc_much(&mut self, pages: usize) -> Option> { + // TODO: alloc more than 64?; + // 优化本函数 + for mut i in 0..(usize::from(self.ppn_end) - usize::from(self.ppn) - pages + 1) { + let mut j = i; + loop { + if j - i >= pages { + let mut ans = Vec::new(); + (i..j).into_iter().for_each(|x| { + self.bits.set_bit(x, true); + ans.push(FrameTracker::new(self.ppn + x)); + }); + return Some(ans); + } + + if self.bits.get_bit(j) == true { + i = j + 1; + break; + } + + j += 1; + } + } + None + } + + /// 释放一个已经使用的页 + /// + /// ppn: PhysPage 要释放的页的地址 + #[inline] + pub fn dealloc(&mut self, ppn: PhysPage) { + self.bits + .set_bit(usize::from(ppn) - usize::from(self.ppn), false); + } +} + +/// 一个总的页帧分配器 +pub struct FrameAllocator(Vec); + +impl FrameAllocator { + /// 创建一个空闲的页帧分配器 + #[inline] + pub const fn new() -> Self { + Self(Vec::new()) + } + + /// 将一块内存放在页帧分配器上 + /// + /// start: usize 内存的起始地址 + /// end: usize 内存的结束地址 + #[inline] + pub fn add_memory_region(&mut self, start: usize, end: usize) { + self.0.push(FrameRegionMap::new(start, end)); + } + + /// 获取页帧分配器中空闲页表的数量 + /// + /// 也就是对所有的页帧分布图中的内存进行和运算 + #[inline] + pub fn get_free_page_count(&self) -> usize { + self.0 + .iter() + .fold(0, |sum, x| sum + x.get_free_page_count()) + } + + /// 申请一个空闲页 + #[inline] + pub fn alloc(&mut self) -> Option { + for frm in &mut self.0 { + let frame = frm.alloc(); + if frame.is_some() { + return frame; + } + } + None + } + + /// 申请多个空闲页, 空闲页是连续的 + /// + /// pages: usize 要申请的页表数量 + /// 在多个页表分布图里查找 + #[inline] + pub fn alloc_much(&mut self, pages: usize) -> Option> { + for frm in &mut self.0 { + let frame = frm.alloc_much(pages); + if frame.is_some() { + return frame; + } + } + None + } + + /// 释放一个页 + #[inline] + pub fn dealloc(&mut self, ppn: PhysPage) { + for frm in &mut self.0 { + if ppn >= frm.ppn && ppn < frm.ppn_end { + frm.dealloc(ppn); + break; + } + } + } +} + +/// 一个总的页帧分配器 +pub static FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAllocator::new()); + +/// 页帧分配器初始化 +pub fn init() { + extern "C" { + fn end(); + } + info!("initialize frame allocator"); + let phys_end = floor(end as usize - VIRT_ADDR_START, PAGE_SIZE) * PAGE_SIZE; + + // 从设备树中获取内存分布 + let mrs = get_memorys(); + + // 在帧分配器中添加内存 + mrs.iter().for_each(|mr| { + if phys_end > mr.start && phys_end < mr.end { + unsafe { + core::slice::from_raw_parts_mut( + phys_end as *mut usize, + (mr.end - phys_end) / size_of::(), + ) + .fill(0); + }; + FRAME_ALLOCATOR.lock().add_memory_region(phys_end, mr.end); + } + }); + + // 确保帧分配器一定能工作 + assert!( + FRAME_ALLOCATOR.lock().0.len() > 0, + "can't find frame to alloc" + ); +} + +/// 申请一个空闲页表 +pub fn frame_alloc() -> Option { + FRAME_ALLOCATOR.lock().alloc() +} + +/// 申请多个空闲连续页表 +pub fn frame_alloc_much(pages: usize) -> Option> { + FRAME_ALLOCATOR.lock().alloc_much(pages) +} + +/// 获取空闲页表数量 +pub fn get_free_pages() -> usize { + FRAME_ALLOCATOR.lock().get_free_page_count() +} + +``` + +以下是分段解释 + +```rust +#![no_std] + +#[macro_use] +extern crate alloc; + +use core::mem::size_of; + +use alloc::vec::Vec; +use arch::{PhysPage, PAGE_SIZE, VIRT_ADDR_START}; +use bit_field::{BitArray, BitField}; +use kheader::mm::get_memorys; +use log::info; +use sync::Mutex; + +pub const fn floor(a: usize, b: usize) -> usize { + return (a + b - 1) / b; +} + +pub const fn ceil_div(a: usize, b: usize) -> usize { + return (a + b - 1) / b; +} + +#[derive(Debug)] +/// 页帧 +/// +/// 用这个代表一个已经被分配的页表,并且利用 Drop 机制保证页表能够顺利被回收 +pub struct FrameTracker(pub PhysPage); + +impl FrameTracker { + pub fn new(ppn: PhysPage) -> Self { + Self(ppn) + } +} + +impl Drop for FrameTracker { + fn drop(&mut self) { + self.0.drop_clear(); + FRAME_ALLOCATOR.lock().dealloc(self.0); + } +} + +/// 页帧分布图 +/// +/// 利用页帧分布图保存页帧分配器中的空闲内存,并且利用 bitArray 记录页帧使用情况 +pub struct FrameRegionMap { + bits: Vec, + ppn: PhysPage, + ppn_end: PhysPage, +} + +impl FrameRegionMap { + /// 创建页帧分布图 + /// + /// start_addr: usize 空闲页帧起始地址 + /// end_addr: usize 空闲页帧结束地址 + #[inline] + pub fn new(start_addr: usize, end_addr: usize) -> Self { + let mut bits = vec![0usize; floor((end_addr - start_addr) / PAGE_SIZE, 64)]; + + // set non-exists memory bit as 1 + for i in (end_addr - start_addr) / PAGE_SIZE..bits.len() * 64 { + bits.set_bit(i, true); + } + + Self { + bits, + ppn: PhysPage::from_addr(start_addr), + ppn_end: PhysPage::from_addr(end_addr), + } + } + + /// 获取页帧分布图中没有使用的页帧数量 + #[inline] + pub fn get_free_page_count(&self) -> usize { + self.bits.iter().fold(0, |mut sum, x| { + if *x == 0 { + sum + 64 + } else { + for i in 0..64 { + sum += match (*x).get_bit(i) { + true => 0, + false => 1, + }; + } + sum + } + }) + } + + /// 在 `bitArray` 指定位置获取一个空闲的页 + /// + /// index: usize 指定的位置 self.bits[index] + #[inline] + fn alloc_in_pos(&mut self, index: usize) -> Option { + for bit_index in 0..64 { + if !self.bits[index].get_bit(bit_index) { + self.bits[index].set_bit(bit_index, true); + return Some(FrameTracker::new(self.ppn + index * 64 + bit_index)); + } + } + None + } +``` + +首先,代码开头的 `#![no_std]` 属性告诉编译器不使用标准库。这通常在嵌入式系统或操作系统内核开发中使用,因为这些环境下无法使用标准库的功能。 + +接下来,通过 `#[macro_use]` 属性导入 `alloc` crate,这个 crate 提供了动态内存分配的功能。然后,使用 `use` 语句导入了一些其他的依赖项,包括 `core::mem::size_of`、`arch::PhysPage`、`PAGE_SIZE`、`VIRT_ADDR_START`、`bit_field::BitArray`、`bit_field::BitField`、`kheader::mm::get_memorys`、`log::info`、以及 `sync::Mutex`。 + +`core::mem::size_of` 函数返回一个类型的大小(以字节为单位)。`arch::PhysPage` 是一个表示物理页的类型。`PAGE_SIZE` 表示页的大小,`VIRT_ADDR_START` 表示虚拟地址的起始地址。`bit_field` crate 提供了位字段的操作功能,`BitArray` 表示位数组,`BitField` 提供了位字段操作的 trait。`kheader::mm::get_memorys` 函数用于获取系统中的内存信息。`log::info` 宏用于记录日志信息。`sync::Mutex` 是一个互斥锁类型,用于实现线程之间的同步。 + +接下来定义了两个辅助函数 `floor` 和 `ceil_div`,它们用于进行整数除法运算。`floor` 函数将两个整数相加后除以另一个整数并向下取整。`ceil_div` 函数将两个整数相加后除以另一个整数并向上取整。 + +接下来是 `FrameTracker` 结构体的定义。它包含一个 `PhysPage` 类型的字段 `ppn`,用于存储物理页的地址。`FrameTracker` 结构体实现了 `Debug` trait,可以使用 `{:?}` 格式化字符串打印它的值。它还实现了 `Drop` trait,当 `FrameTracker` 对象被销毁时会自动执行 `drop` 方法。在 `drop` 方法中,它调用了 `drop_clear` 方法清除页面的内容,并通过 `FRAME_ALLOCATOR` 对象的 `dealloc` 方法释放页面。 + +接下来定义了一个名为 `FrameRegionMap` 的结构体,用于管理页帧的分配和释放。它包含了三个字段:`bits`、`ppn` 和 `ppn_end`。`bits` 是一个 `Vec` 类型的数组,用于记录页帧的使用情况。`ppn` 和 `ppn_end` 是 `PhysPage` 类型的字段,用于表示可用页帧的起始和结束地址。 + +`FrameRegionMap` 结构体实现了一些方法。首先是 `new` 方法,它接受起始地址和结束地址作为参数,创建一个新的 `FrameRegionMap` 对象。在该方法中,首先计算出需要多少个 `usize` 类型的元素来存储所有的页帧,并创建了一个长度为该值的 `bits` 数组。然后,它将超出可用范围的页帧(即不属于空闲区域的页帧)标记为已使用,即将相应的位设置为 1。这样,`bits` 数组中的每个元素都代表了 64 个页帧的使用情况。 + +接下来是 `get_free_page_count` 方法,用于获取页帧分布图中未使用的页帧数量。它遍历 `bits` 数组,对于每个元素,如果它的值为 0,就将 64 加到计数器 `sum` 上;否则,遍历元素的每一位,如果位为 0,就将计数器 `sum` 加 1。最后返回计数器的值,即未使用的页帧数量。 + +接下来是 `alloc_in_pos` 方法,用于在指定位置分配一个空闲页帧。它接受一个 `usize` 类型的参数 `pos`,表示要分配的页帧的位置。在该方法中,首先计算出 `pos` 在 `bits` 数组中的索引和位偏移量。然后,从索引开始遍历 `bits` 数组,对于每个元素,如果它的值不等于 `usize::MAX`,说明还有未使用的页帧,就通过 `BitArray` 的 `get` 方法获取该元素的相应位的值。如果位为 0,说明该页帧未被使用,将其设置为 1,并返回分配的页帧地址。如果遍历完所有的元素都没有找到未使用的页帧,就返回 `None`,表示分配失败。 + +最后是 `dealloc` 方法,用于释放已分配的页帧。它接受一个 `PhysPage` 类型的参数 `ppn`,表示要释放的页帧的地址。在该方法中,首先计算出 `ppn` 在 `bits` 数组中的索引和位偏移量。然后,通过 `BitArray` 的 `get` 方法获取该元素的相应位的值,如果位为 1,说明该页帧已被使用,将其设置为 0,表示释放该页帧。 + +总结一下,这段代码实现了一个简单的页帧分配器,用于管理系统中的物理页帧。它通过维护一个位数组来记录页帧的使用情况,提供了分配和释放页帧的功能。通过使用位数组,可以高效地分配和释放物理页帧。 + +```rust + /// 申请一个空闲页 + #[inline] + pub fn alloc(&mut self) -> Option { + for i in 0..self.bits.len() { + if self.bits[i] != usize::MAX { + return self.alloc_in_pos(i); + } + } + None + } + + /// 申请多个空闲页, 空闲页是连续的 + /// + /// pages: usize 要申请的页表数量 + #[allow(unused_assignments)] + pub fn alloc_much(&mut self, pages: usize) -> Option> { + // TODO: alloc more than 64?; + // 优化本函数 + for mut i in 0..(usize::from(self.ppn_end) - usize::from(self.ppn) - pages + 1) { + let mut j = i; + loop { + if j - i >= pages { + let mut ans = Vec::new(); + (i..j).into_iter().for_each(|x| { + self.bits.set_bit(x, true); + ans.push(FrameTracker::new(self.ppn + x)); + }); + return Some(ans); + } + + if self.bits.get_bit(j) == true { + i = j + 1; + break; + } + + j += 1; + } + } + None + } + + /// 释放一个已经使用的页 + /// + /// ppn: PhysPage 要释放的页的地址 + #[inline] + pub fn dealloc(&mut self, ppn: PhysPage) { + self.bits + .set_bit(usize::from(ppn) - usize::from(self.ppn), false); + } +} + +/// 一个总的页帧分配器 +pub struct FrameAllocator(Vec); + +impl FrameAllocator { + /// 创建一个空闲的页帧分配器 + #[inline] + pub const fn new() -> Self { + Self(Vec::new()) + } + + /// 将一块内存放在页帧分配器上 + /// + /// start: usize 内存的起始地址 + /// end: usize 内存的结束地址 + #[inline] + pub fn add_memory_region(&mut self, start: usize, end: usize) { + self.0.push(FrameRegionMap::new(start, end)); + } + + /// 获取页帧分配器中空闲页表的数量 + /// + /// 也就是对所有的页帧分布图中的内存进行和运算 + #[inline] + pub fn get_free_page_count(&self) -> usize { + self.0 + .iter() + .fold(0, |sum, x| sum + x.get_free_page_count()) + } + + /// 申请一个空闲页 + #[inline] + pub fn alloc(&mut self) -> Option { + for frm in &mut self.0 { + let frame = frm.alloc(); + if frame.is_some() { + return frame; + } + } + None + } + + /// 申请多个空闲页, 空闲页是连续的 + /// + /// pages: usize 要申请的页表数量 + /// 在多个页表分布图里查找 + #[inline] + pub fn alloc_much(&mut self, pages: usize) -> Option> { + for frm in &mut self.0 { + let frame = frm.alloc_much(pages); + if frame.is_some() { + return frame; + } + } + None + } + + /// 释放一个页 + #[inline] + pub fn dealloc(&mut self, ppn: PhysPage) { + for frm in &mut self.0 { + if ppn >= frm.ppn && ppn < frm.ppn_end { + frm.dealloc(ppn); + break; + } + } + } +} +``` + +首先,代码中定义了一个名为 `FrameRegionMap` 的结构体,表示一个页帧分布图。每个 `FrameRegionMap` 对象都管理一块连续的物理内存区域,并跟踪该区域中每个页帧的使用情况。 + +`FrameRegionMap` 结构体的定义如下: + +```rust +pub struct FrameRegionMap { + bits: BitSlice, + ppn: PhysPage, + ppn_end: PhysPage, +} +``` + +- `bits` 字段是一个位切片(`BitSlice`),用于记录每个页帧的使用情况。位切片是一种可以高效地访问和操作位的数据结构。 +- `ppn` 和 `ppn_end` 字段表示该页帧分布图所管理的可用页帧的起始和结束地址(以 `PhysPage` 类型表示)。 + +接下来,代码定义了 `FrameRegionMap` 结构体的一些方法: + +1. **`new` 方法**:创建一个新的 `FrameRegionMap` 对象,并初始化 `bits` 数组。具体步骤如下: + + - 计算需要多少个 `usize` 类型的元素来存储所有的页帧(`bits` 数组的长度)。 + - 创建一个长度为该值的 `bits` 数组,并将所有位初始化为 0。 + - 将超出可用范围的页帧(即不属于空闲区域的页帧)标记为已使用,即将相应的位设置为 1。 + +1. **`get_free_page_count` 方法**:获取页帧分布图中未使用的页帧数量。具体步骤如下: + + - 遍历 `bits` 数组的每个元素。 + - 对于每个元素,如果它的值为 0,说明该元素对应的 64 个位都是未使用的页帧,所以将计数器 `sum` 加 64。 + - 如果元素的值不为 0,则遍历元素的每一位,如果位为 0,说明对应的页帧是未使用的,所以将计数器 `sum` 加 1。 + - 最后返回计数器 `sum` 的值,即未使用的页帧数量。 + +1. **`alloc` 方法**:在页帧分布图中申请一个空闲页帧。具体步骤如下: + + - 遍历 `bits` 数组的每个元素,查找第一个不等于 `usize::MAX` 的元素。 + - 如果找到了这样的元素,说明至少有一个未使用的页帧,可以进行分配。 + - 调用 `alloc_in_pos` 方法进行具体的分配操作,传入找到的元素的索引值 `i`。 + - 如果成功分配到页帧,就返回对应的 `FrameTracker` 对象;否则,返回 `None`。 + +1. **`alloc_much` 方法**:申请多个连续的空闲页帧。具体步骤如下: + + - 使用两个循环变量 `i` 和 `j`,初始化为 0。 + - 外层循环(以 `i` 为循环变量)遍历从 0 到 `(usize::from(self.ppn_end) - usize::from(self.ppn) - pages + 1)` 的范围。 + - 内层循环(以 `j` 为循环变量)从 `i` 开始,逐个递增,直到找到连续的 `pages` 个未使用的页帧或者超出可用范围。 + - 如果找到了连续的 `pages` 个未使用的页帧,就进行分配操作: + - 创建一个空的 `Vec` 对象,用于存储分配的页帧。 + - 遍历从 `i` 到 `j` 的范围,将每个未使用的页帧的地址转换为 `FrameTracker` 对象,并添加到 `Vec` 中。 + - 将相应的位数组元素的对应位设置为 1,表示这些页帧已被分配使用。 + - 返回分配的页帧的地址作为结果。 + - 如果没有找到连续的 `pages` 个未使用的页帧,就返回 `None`。 + +1. **`dealloc` 方法**:释放已经使用的页帧。具体步骤如下: + + - 根据传入的页帧地址找到对应的位数组元素。 + - 将相应的位设置为 0,表示释放该页帧。 + +此外,代码还定义了一个名为 `FrameAllocator` 的结构体,表示整个页帧分配器。`FrameAllocator` 结构体包含一个 `Vec` 字段,用于存储多个页帧分布图。 + +`FrameAllocator` 结构体的定义如下: + +```rust +pub struct FrameAllocator { + regions: Vec, +} +``` + +`FrameAllocator` 结构体提供了一些方法: + +1. **`new` 方法**:创建一个空闲的页帧分配器。它只是简单地初始化了 `Vec` 字段为空。 + +1. **`add_memory_region` 方法**:将一块内存添加到页帧分配器中。具体步骤如下: + + - 接收内存的起始地址和结束地址作为参数。 + - 在 `Vec` 中添加一个新的 `FrameRegionMap` 对象,以管理该内存区域的页帧。 + +1. **`get_free_page_count` 方法**:获取页帧分配器中空闲页帧的数量。具体步骤如下: + + - 遍历所有的页帧分布图。 + - 对于每个 `FrameRegionMap` 对象,调用其 `get_free_page_count` 方法,获取该分布图中的空闲页帧数量。 + - 将各个分布图的空闲页帧数量累加起来,并返回结果。 + +1. **`alloc` 方法**:在页帧分配器中申请一个空闲页帧。具体步骤如下: + + - 遍历所有的页帧分布图。 + - 对于每个 `FrameRegionMap` 对象,调用其 `alloc` 方法,尝试分配一个空闲页帧。 + - 如果成功分配到页帧,就返回分配的页帧地址;如果所有的分布图都无法分配到页帧,则返回 `None`。 + +1. **`alloc_much` 方法**:申请多个连续的空闲页帧。具体步骤如下: + + - 遍历所有的页帧分布图。 + - 对于每个 `FrameRegionMap` 对象,调用其 `alloc_much` 方法,尝试分配多个连续的空闲页帧。 + - 如果成功分配到连续的页帧,就返回分配的页帧地址;如果所有的分布图都无法分配到连续的页帧,则返回 `None`。 + +1. **`dealloc` 方法**:释放一个已经使用的页帧。具体步骤如下: + + - 遍历所有的页帧分布图。 + - 对于每个 `FrameRegionMap` 对象,调用其 `dealloc` 方法,释放指定的页帧。 + +通过添加内存区域,可以将不同的物理内存映射到页帧分配器,从而实现对整个系统中可用页帧的管理。`FrameAllocator` 提供了一组方法来方便地管理和操作页帧的分配和释放。 + +总结起来,这段代码实现了一个灵活的页帧分配器,它可以管理多个不连续的物理内存区域,并提供了分配和释放页帧的功能。这对于操作系统或其他需要管理物理 + +```rust +/// 一个总的页帧分配器 +pub static FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAllocator::new()); + +/// 页帧分配器初始化 +pub fn init() { + extern "C" { + fn end(); + } + info!("initialize frame allocator"); + let phys_end = floor(end as usize - VIRT_ADDR_START, PAGE_SIZE) * PAGE_SIZE; + + // 从设备树中获取内存分布 + let mrs = get_memorys(); + + // 在帧分配器中添加内存 + mrs.iter().for_each(|mr| { + if phys_end > mr.start && phys_end < mr.end { + unsafe { + core::slice::from_raw_parts_mut( + phys_end as *mut usize, + (mr.end - phys_end) / size_of::(), + ) + .fill(0); + }; + FRAME_ALLOCATOR.lock().add_memory_region(phys_end, mr.end); + } + }); + + // 确保帧分配器一定能工作 + assert!( + FRAME_ALLOCATOR.lock().0.len() > 0, + "can't find frame to alloc" + ); +} + +/// 申请一个空闲页表 +pub fn frame_alloc() -> Option { + FRAME_ALLOCATOR.lock().alloc() +} + +/// 申请多个空闲连续页表 +pub fn frame_alloc_much(pages: usize) -> Option> { + FRAME_ALLOCATOR.lock().alloc_much(pages) +} + +/// 获取空闲页表数量 +pub fn get_free_pages() -> usize { + FRAME_ALLOCATOR.lock().get_free_page_count() +} + +``` + +当我们运行操作系统或应用程序时,需要使用物理内存来存储数据和代码。物理内存被划分为固定大小的页帧(Page Frame),而操作系统和应用程序以页的形式进行内存管理。页帧分配器是一个用于管理物理内存的模块,它负责分配和释放页帧,以满足操作系统和应用程序的内存需求。 + +让我们逐行详细解释这段代码: + +```rust +/// 一个总的页帧分配器 +pub static FRAME_ALLOCATOR: Mutex = Mutex::new(FrameAllocator::new()); +``` + +这行代码定义了一个名为 `FRAME_ALLOCATOR` 的静态变量,它的类型是 `Mutex`。`Mutex` 是一个互斥锁,用于在多线程环境中保护共享数据的访问。`FrameAllocator` 是一个用于管理页帧的结构体。 + +```rust +/// 页帧分配器初始化 +pub fn init() { + extern "C" { + fn end(); + } + info!("initialize frame allocator"); + let phys_end = floor(end as usize - VIRT_ADDR_START, PAGE_SIZE) * PAGE_SIZE; + + // 从设备树中获取内存分布 + let mrs = get_memorys(); + + // 在帧分配器中添加内存 + mrs.iter().for_each(|mr| { + if phys_end > mr.start && phys_end < mr.end { + unsafe { + core::slice::from_raw_parts_mut( + phys_end as *mut usize, + (mr.end - phys_end) / size_of::(), + ) + .fill(0); + }; + FRAME_ALLOCATOR.lock().add_memory_region(phys_end, mr.end); + } + }); + + // 确保帧分配器一定能工作 + assert!( + FRAME_ALLOCATOR.lock().0.len() > 0, + "can't find frame to alloc" + ); +} +``` + +这是一个用于初始化页帧分配器的函数。它的主要任务是将可用的物理内存添加到帧分配器中。让我们逐步解释此函数的实现: + +- 首先,通过使用 `extern "C"` 声明了一个名为 `end` 的函数,它是一个外部函数,用于获取程序的结束地址。 + +- 然后,打印日志信息 "initialize frame allocator",表示开始初始化帧分配器。 + +- 接下来,通过计算 `end` 函数的地址减去虚拟地址的起始地址 `VIRT_ADDR_START`,并向下取整为页的大小 `PAGE_SIZE` 的倍数,得到物理内存的结束地址 `phys_end`。这个地址表示当前程序的结束地址,即程序的代码和数据所占用的物理内存的最后一个地址。 + +- 然后,调用 `get_memorys()` 函数从设备树中获取内存分布信息,返回一个内存区域的数组 `mrs`。设备树是一种描述硬件设备的数据结构,它提供了有关系统中可用内存的信息。 + +- 接下来,对于每个内存区域 `mr`,通过比较 `phys_end` 是否在内存区域的范围内,来确定是否将该内存区域添加到帧分配器中。 + +- 在添加内存区域之前,首先使用 `core::slice::from_raw_parts_mut()` 函数将从 `phys_end` 开始的一段内存转换为可变的 `usize` 类型的切片,并将该切片的元素全部初始化为 0。 + +- 然后,通过调用 `FRAME_ALLOCATOR.lock().add_memory_region()` 方法将内存区域添加到帧分配器中。 + +- 最后,通过断言确保帧分配器中至少有一个可用的页帧,如果没有可用的页帧,则会触发断言失败。 + +```rust +/// 申请一个空闲页表 +pub fn frame_alloc() -> Option { + FRAME_ALLOCATOR.lock().alloc() +} +``` + +这是一个用于申请一个空闲页帧的函数。它的实现如下: + +- 首先,通过调用 `FRAME_ALLOCATOR` 的 `lock()` 方法获取互斥锁,这是为了在多线程环境中保护帧分配器的访问。 + +- 然后,调用帧分配器的 `alloc()` 方法来申请一个空闲页帧。该方法会返回一个 `Option` 类型的结果,表示成功申请到一个空闲页帧或者没有可用的空闲页帧。 + +- 最后,函数返回申请到的空闲页帧。如果帧分配器返回的结果是 `Some(frame)`,则表示成功申请到一个页帧,可以通过 `frame` 来访问该页帧;如果结果是 `None`,则表示当前没有可用的空闲页帧。 + +```rust +/// 申请多个空闲连续页表 +pub fn frame_alloc_much(pages: usize) -> Option> { + FRAME_ALLOCATOR.lock().alloc_much(pages) +} +``` + +这是一个用于申请多个连续的空闲页帧的函数。它的实现如下: + +- 首先,通过调用 `FRAME_ALLOCATOR` 的 `lock()` 方法获取互斥锁,这是为了在多线程环境中保护帧分配器的访问。 + +- 然后,调用帧分配器的 `alloc_much(pages)` 方法来申请指定数量的连续空闲页帧。该方法会返回一个 `Option>` 类型的结果,表示成功申请到一组连续的空闲页帧或者没有足够的连续空闲页帧可用。 + +- 最后,函数返回申请到的连续空闲页帧。如果帧分配器返回的结果是 `Some(frames)`,则表示成功申请到一组连续的页帧,可以通过 `frames` 来访问这些页帧;如果结果是 `None`,则表示当前没有足够的连续空闲页帧可用。 + +```rust +/// 获取空闲页表数量 +pub fn get_free_pages() -> usize { + FRAME_ALLOCATOR.lock().get_free_page_count() +} +``` + +这是一个用于获取当前可用的空闲页帧数量的函数。它的实现如下: + +- 首先,通过调用 `FRAME_ALLOCATOR` 的 `lock()` 方法获取互斥锁,这是为了在多线程环境中保护帧分配器的访问。 + +- 然后,调用帧分配器的 `get_free_page_count()` 方法获取当前可用的空闲页帧数量。 + +- 最后,函数返回可用的空闲页帧数量,它是一个 `usize` 类型的结果。 + +## 设计亮点 + +1. **支持多个内存区域**:该页帧分配器通过 `FrameRegionMap` 结构体和 `FrameAllocator` 结构体的组合,可以管理多个不连续的内存区域。这样的设计使得页帧分配器可以有效地管理不同物理内存区域的页帧分配和释放。 +2. **位图管理页帧状态**:在 `FrameRegionMap` 结构体中使用位图记录页帧的使用状态。这种位图的设计可以高效地表示页帧的使用情况,并且在分配和释放页帧时具有较低的时间和空间复杂度。 +3. **支持连续页帧分配**:`alloc_much()` 方法提供了连续页帧分配的功能,可以根据需求申请多个连续的空闲页帧。通过遍历位图找到连续的可用位置进行分配,使得连续页帧的分配操作更加高效。 +4. **线程安全性**:通过使用 `Mutex` 对全局的 `FRAME_ALLOCATOR` 进行包装,确保在多线程环境下的互斥访问。这样可以避免多个线程同时访问和修改页帧分配器的状态,保证数据的一致性和安全性。 +5. **模块化设计**:将页帧分配器的相关功能封装成结构体和方法,并提供了对外的接口函数。这种模块化的设计使得代码结构清晰,易于理解和维护,并且方便其他模块使用和扩展。 \ No newline at end of file diff --git "a/docs/\351\241\271\347\233\256\347\273\223\346\236\204.md" "b/docs/\351\241\271\347\233\256\347\273\223\346\236\204.md" new file mode 100644 index 00000000..0221b03f --- /dev/null +++ "b/docs/\351\241\271\347\233\256\347\273\223\346\236\204.md" @@ -0,0 +1,21 @@ +# 项目结构 + +``` +├── arch //该目录为ByteOS的架构支持,目前支持了RISCV64 +├── Cargo.lock +├── Cargo.toml +├── crates //该目录为ByteOS的辅助功能crates,包括错误回溯,时间戳和虚拟文件系统以及为华山派开发板编写的SD卡驱动 +├── cv1811h-burn.sh +├── docs //该目录为项目的文档,需要查询文档可在该目录下查看 +├── drivers //该目录为ByteOS的设备驱动,包括K210的SD卡驱动,虚拟网卡驱动等 +├── kernel //该目录为ByteOS内核源代码 +├── Makefile +├── modules //该目录为ByteOS的功能模块,如日志,内存分配,设备管理,文件系统等 +├── netperf.log +├── README.md +├── run.png +├── rust-toolchain.toml +├── target +└── tools +``` + diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 49ac900e..cd410d4b 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,7 +4,44 @@ version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +net = [] + +[build-dependencies] +toml = "0.5.2" +serde = "1.0.136" +serde_derive = "1.0.136" [dependencies] -logging = { path = "../modules/logging" } -panic_handler = { path = "../modules/panic_handler" } \ No newline at end of file +allocator = { git = "https://github.com/Byte-OS/allocator.git", rev = "c6ce949146d5feab1d406502b19b035f5d392c35"} +frame_allocator = { git = "https://github.com/Byte-OS/bit_frame_allocator.git" } +logging = { git = "https://github.com/Byte-OS/logging.git", features = []} +log = "0.4" +devices = { git = "https://github.com/Byte-OS/devices.git" } +hal = { git = "https://github.com/Byte-OS/hal.git" } +polyhal = { git = "https://github.com/Byte-OS/polyhal.git", features = ["trap", "graphic", "logger"]} +fs = { git = "https://github.com/Byte-OS/fs.git" } +fdt = "0.1.5" +executor = { git = "https://github.com/Byte-OS/executor.git" } +xmas-elf = "0.9.0" +sync = { git = "https://github.com/Byte-OS/sync.git" } +bitflags = "2.0.2" +signal = { git = "https://github.com/Byte-OS/signal.git" } +bit_field = "0.10.1" +lose-net-stack = { git = "https://github.com/byte-os/lose-net-stack", rev = "bb99460", features = ["log"]} +# lose-net-stack = { path = "../../lose-net-stack", features = ["log"]} +vfscore = { git = "https://github.com/Byte-OS/vfscore.git" } +async-recursion = "1.1.0" +futures-lite = { version = "1.13.0", default-features = false, features=["alloc"] } +# backtrace = { path = "../crates/backtrace" } +hashbrown = "0.14" +cfg-if = "1.0.0" + +num-traits = { version = "0.2", default-features = false} +num-derive = "0.4" + +kvirtio = { git = "https://github.com/Byte-OS/driver-kvirtio.git" } +kgoldfish-rtc = { git = "https://github.com/Byte-OS/driver-kgoldfish-rtc.git" } +kramdisk = { git = "https://github.com/Byte-OS/kramdisk.git" } +general-plic = { git = "https://github.com/Byte-OS/driver-general-plic.git" } +ns16550a = { git = "https://github.com/Byte-OS/driver-ns16550a.git" } diff --git a/kernel/build.rs b/kernel/build.rs new file mode 100644 index 00000000..c5a9c649 --- /dev/null +++ b/kernel/build.rs @@ -0,0 +1,78 @@ +#![feature(lazy_cell)] + +use std::io::Result; +use std::{env, fs, path::PathBuf}; + +#[allow(unused_macros)] +macro_rules! display { + ($fmt:expr) => (println!("cargo:warning={}", format!($fmt))); + ($fmt:expr, $($arg:tt)*) => (println!(concat!("cargo:warning=", $fmt), $($arg)*)); +} + +// write module config to file. +fn write_module_config(driver_list: Vec) { + let manifest_path = PathBuf::from(env::var("OUT_DIR").expect("can't find manifest dir")); + let mut module_file_content = String::new(); + driver_list.into_iter().for_each(|module| { + if module.is_empty() { + return; + }; + module_file_content.push_str(&format!("extern crate {};\n", module.replace('-', "_"))) + }); + fs::write(manifest_path.join("drivers.rs"), module_file_content) + .expect("can't write file to manifest dir"); +} + +fn main() { + let drivers = std::env::var("CARGO_CFG_DRIVER") + .unwrap_or(String::from("")) + .split(',') + .map(|x| x.trim().to_owned()) + .collect(); + + // write module configuration to OUT_PATH, then it will be included in the main.rs + write_module_config(drivers); + gen_linker_script(&env::var("CARGO_CFG_BOARD").expect("can't find board")) + .expect("can't generate linker script"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_TARGET_ARCH"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_KERNEL_BASE"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_BOARD"); + println!("cargo:rerun-if-env-changed=CARGO_CFG_DRIVER"); + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=linker.lds.S"); +} + +fn gen_linker_script(platform: &str) -> Result<()> { + let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("can't find target"); + let board = env::var("CARGO_CFG_BOARD").unwrap_or("qemu".to_string()); + let fname = format!("linker_{}_{}.lds", arch, platform); + let (output_arch, kernel_base) = if arch == "x86_64" { + ("i386:x86-64", "0xffffff8000200000") + } else if arch.contains("riscv64") { + ("riscv", "0xffffffc080200000") // OUTPUT_ARCH of both riscv32/riscv64 is "riscv" + } else if arch.contains("aarch64") { + // ("aarch64", "0x40080000") + ("aarch64", "0xffffff8040080000") + // ("aarch64", "0xffff000040080000") + } else if arch.contains("loongarch64") { + match board.as_str() { + "2k1000" => ("loongarch64", "0x9000000098000000"), + _ => ("loongarch64", "0x9000000090000000"), + } + } else { + (arch.as_str(), "0") + }; + let ld_content = std::fs::read_to_string("linker.lds.S")?; + let ld_content = ld_content.replace("%ARCH%", output_arch); + // let ld_content = ld_content.replace( + // "%KERNEL_BASE%", + // &env::var("CARGO_CFG_KERNEL_BASE").expect("can't find KERNEL_BASE cfg"), + // ); + let ld_content = ld_content.replace("%KERNEL_BASE%", kernel_base); + let ld_content = ld_content.replace("%SMP%", "4"); + + std::fs::write(&fname, ld_content)?; + println!("cargo:rustc-link-arg=-Tkernel/{}", fname); + println!("cargo:rerun-if-env-changed=CARGO_CFG_KERNEL_BASE"); + Ok(()) +} diff --git a/kernel/linker.lds.S b/kernel/linker.lds.S new file mode 100644 index 00000000..3b2621e0 --- /dev/null +++ b/kernel/linker.lds.S @@ -0,0 +1,54 @@ +OUTPUT_ARCH(%ARCH%) +ENTRY(_start) + +BASE_ADDRESS = %KERNEL_BASE%; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + _skernel = .; + + .text ALIGN(4K): { + stext = .; + *(.text.entry) + *(.text .text.*) + etext = .; + } + + .rodata ALIGN(4K): { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data ALIGN(4K): { + . = ALIGN(4K); + *(.data.prepage .data.prepage.*) + . = ALIGN(4K); + _sdata = .; + *(.data .data.*) + *(.sdata .sdata.*) + _edata = .; + } + + .sigtrx ALIGN(4K): { + *(.sigtrx .sigtrx.*) + } + + .bss ALIGN(4K): { + _load_end = .; + *(.bss.stack) + _sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + _ebss = .; + } + + PROVIDE(end = .); + /DISCARD/ : { + *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) + } +} \ No newline at end of file diff --git a/kernel/src/banner.txt b/kernel/src/banner.txt new file mode 100644 index 00000000..0cbd574e --- /dev/null +++ b/kernel/src/banner.txt @@ -0,0 +1,9 @@ + + ____ _ ____ _____ + | _ \ | | / __ \ / ____| + | |_) |_ _| |_ ___| | | | (___ + | _ <| | | | __/ _ \ | | |\___ \ + | |_) | |_| | || __/ |__| |____) | + |____/ \__, |\__\___|\____/|_____/ + __/ | + |___/ diff --git a/kernel/src/epoll/mod.rs b/kernel/src/epoll/mod.rs new file mode 100644 index 00000000..f3ed689a --- /dev/null +++ b/kernel/src/epoll/mod.rs @@ -0,0 +1,83 @@ +use hashbrown::HashMap; +use num_derive::FromPrimitive; +use sync::Mutex; +use vfscore::{INodeInterface, PollEvent}; + +#[repr(C)] +#[derive(Clone, Debug)] +pub struct EpollEvent { + pub events: EpollEventType, + pub data: u64, +} + +bitflags! { + /// Epoll Event Type, it is similar as the PollEvent type. + #[derive(Clone, Debug)] + pub struct EpollEventType: u32 { + const EPOLLIN = 0x001; + const EPOLLOUT = 0x004; + const EPOLLERR = 0x008; + const EPOLLHUP = 0x010; + const EPOLLPRI = 0x002; + const EPOLLRDNORM = 0x040; + const EPOLLRDBAND = 0x080; + const EPOLLWRNORM = 0x100; + const EPOLLWRBAND= 0x200; + const EPOLLMSG = 0x400; + const EPOLLRDHUP = 0x2000; + const EPOLLEXCLUSIVE = 0x1000_0000; + const EPOLLWAKEUP = 0x2000_0000; + const EPOLLONESHOT = 0x4000_0000; + const EPOLLET = 0x8000_0000; + + } +} + +impl EpollEventType { + pub fn to_poll(&self) -> PollEvent { + PollEvent::from_bits_truncate(self.bits() as u16) + } +} + +#[derive(Debug)] +pub struct EpollFile { + pub data: Mutex>, + pub flags: usize, +} + +impl EpollFile { + pub fn new(flags: usize) -> Self { + EpollFile { + data: Mutex::new(HashMap::new()), + flags, + } + } + + pub fn ctl(&self, ctl: EpollCtl, fd: usize, ev: EpollEvent) { + match ctl { + EpollCtl::ADD => { + self.data.lock().insert(fd, ev); + } + EpollCtl::DEL => { + self.data.lock().remove(&fd); + } + EpollCtl::MOD => { + if let Some(x) = self.data.lock().get_mut(&fd) { + *x = ev; + } + } + } + } +} + +impl INodeInterface for EpollFile {} + +#[repr(u8)] +#[derive(Debug, Eq, PartialEq, FromPrimitive)] +#[allow(clippy::upper_case_acronyms)] +/// epoll_ctl +pub enum EpollCtl { + ADD = 1, + DEL = 2, + MOD = 3, +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7ac4f646..8059183d 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -1,16 +1,240 @@ #![no_main] #![no_std] +#![feature(exclusive_range_pattern)] +#![feature(extract_if)] +#![feature(ip_in_core)] +#![feature(async_closure)] +#![feature(let_chains)] +#![feature(panic_info_message)] +#![feature(stdsimd)] + +// include modules drivers +// mod drivers; +include!(concat!(env!("OUT_DIR"), "/drivers.rs")); #[macro_use] extern crate logging; -use panic_handler as _; +#[macro_use] +extern crate alloc; +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate log; + +mod epoll; +// mod modules; +mod panic; +mod socket; +mod syscall; +mod tasks; +mod user; + +use core::sync::atomic::{AtomicBool, Ordering}; + +use devices::{self, get_int_device, VIRT_ADDR_START}; +use executor::current_task; +use frame_allocator::{self, frame_alloc_persist, frame_unalloc}; +use polyhal::addr::{PhysPage, VirtPage}; +use polyhal::common::{get_fdt, get_mem_areas, PageAlloc}; +use polyhal::irq::IRQ; +use polyhal::trap::TrapType; +use polyhal::trapframe::{TrapFrame, TrapFrameArgs}; +use tasks::UserTask; +use user::user_cow_int; +use vfscore::OpenFlags; + +use crate::tasks::{current_user_task, FileItem}; +use crate::user::task_ilegal; + +pub struct PageAllocImpl; + +impl PageAlloc for PageAllocImpl { + #[inline] + fn alloc(&self) -> PhysPage { + unsafe { frame_alloc_persist().expect("can't alloc frame") } + } + + #[inline] + fn dealloc(&self, ppn: PhysPage) { + unsafe { frame_unalloc(ppn) } + ppn.drop_clear(); + } +} + +#[polyhal::arch_interrupt] +/// Handle kernel interrupt +fn kernel_interrupt(cx_ref: &mut TrapFrame, trap_type: TrapType) { + match trap_type { + TrapType::StorePageFault(addr) + | TrapType::InstructionPageFault(addr) + | TrapType::LoadPageFault(addr) => { + if addr > VIRT_ADDR_START { + panic!( + "kernel page error: {:#x} sepc: {:#x}", + addr, + cx_ref[TrapFrameArgs::SEPC] + ); + } + // judge whether it is trigger by a user_task handler. + if let Ok(task) = current_task().downcast_arc::() { + let cx_ref = task.force_cx_ref(); + if task.pcb.is_locked() { + // task.pcb.force_unlock(); + unsafe { + task.pcb.force_unlock(); + } + } + user_cow_int(task, cx_ref, addr); + } else { + panic!("page fault: {:#x?}", trap_type); + } + } + TrapType::IllegalInstruction(addr) => { + if addr > VIRT_ADDR_START { + return; + } + let task = current_user_task(); + let vpn = VirtPage::from_addr(addr); + warn!( + "illegal instruction fault @ {:#x} vpn: {} ppn: {:?}", + addr, + vpn, + task.page_table.translate(addr.into()), + ); + warn!("the fault occurs @ {:#x}", cx_ref[TrapFrameArgs::SEPC]); + // warn!("user_task map: {:#x?}", task.pcb.lock().memset); + warn!( + "mapped ppn addr: {:#x} @ {:?}", + cx_ref[TrapFrameArgs::SEPC], + task.page_table + .translate(cx_ref[TrapFrameArgs::SEPC].into()) + ); + task_ilegal(&task, cx_ref[TrapFrameArgs::SEPC], cx_ref); + // panic!("illegal Instruction") + // let signal = task.tcb.read().signal.clone(); + // if signal.has_sig(SignalFlags::SIGSEGV) { + // task.exit_with_signal(SignalFlags::SIGSEGV.num()); + // } else { + // return UserTaskControlFlow::Break + // } + // current_user_task() + // .tcb + // .write() + // .signal + // .add_signal(SignalFlags::SIGSEGV); + // return UserTaskControlFlow::Break; + } + TrapType::SupervisorExternal => { + get_int_device().try_handle_interrupt(u32::MAX); + } + _ => { + // warn!("trap_type: {:?} context: {:#x?}", trap_type, cx); + // debug!("kernel_interrupt"); + } + }; +} + +/// The kernel entry +#[polyhal::arch_entry] +fn main(hart_id: usize) { + static BOOT_CORE_FLAGS: AtomicBool = AtomicBool::new(false); + IRQ::int_disable(); + // Ensure this is the first core + if BOOT_CORE_FLAGS + .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) + .is_ok() + { + extern "C" { + fn start(); + fn end(); + } + + allocator::init(); + + let str = include_str!("banner.txt"); + println!("{}", str); + + // initialize logging module + // logging::init(option_env!("LOG")); + + polyhal::common::init(&PageAllocImpl); + get_mem_areas().into_iter().for_each(|(start, size)| { + info!("memory area: {:#x} - {:#x}", start, start + size); + frame_allocator::add_frame_map(start, start + size); + }); + + println!("run kernel @ hart {}", hart_id); + + info!("program size: {}KB", (end as usize - start as usize) / 1024); + + // Boot all application core. + // polyhal::multicore::MultiCore::boot_all(); + + devices::prepare_drivers(); + + if let Some(fdt) = get_fdt() { + for node in fdt.all_nodes() { + devices::try_to_add_device(&node); + } + } + + // get devices and init + devices::regist_devices_irq(); + + // TODO: test ebreak + // Instruction::ebreak(); + + // initialize filesystem + fs::init(); + { + FileItem::fs_open("/var", OpenFlags::O_DIRECTORY) + .expect("can't open /var") + .mkdir("tmp") + .expect("can't create tmp dir"); + + // Initialize the Dentry node. + // dentry::dentry_init(rootfs); + // FileItem::fs_open("/bin", OpenFlags::O_DIRECTORY) + // .expect("can't open /bin") + // .link( + // "sleep", + // FileItem::fs_open("busybox", OpenFlags::NONE) + // .expect("not hava busybox file") + // .inner + // .clone(), + // ) + // .expect("can't link busybox to /bin/sleep"); + } + + // enable interrupts + IRQ::int_enable(); + + // cache task with task templates + // crate::syscall::cache_task_template("/bin/busybox").expect("can't cache task"); + // crate::syscall::cache_task_template("./busybox").expect("can't cache task"); + // crate::syscall::cache_task_template("busybox").expect("can't cache task"); + // crate::syscall::cache_task_template("./runtest.exe").expect("can't cache task"); + // crate::syscall::cache_task_template("entry-static.exe").expect("can't cache task"); + // crate::syscall::cache_task_template("libc.so").expect("can't cache task"); + // crate::syscall::cache_task_template("lmbench_all").expect("can't cache task"); + + // loop { + // info!("3"); + // } + + // init kernel threads and async executor + tasks::init(); + log::info!("run tasks"); + // loop { arch::wfi() } + tasks::run_tasks(); + + println!("Task All Finished!"); + } else { + println!("run kernel @ hart {}", hart_id); -#[no_mangle] -extern "Rust" fn main(hart_id: usize) { - if hart_id != 0 { - loop {} + IRQ::int_enable(); + // loop { arch::wfi() } + tasks::run_tasks(); + info!("shutdown ap core"); } - // initialize logging module - logging::init(); - println!("Hello, world!"); } diff --git a/kernel/src/panic.rs b/kernel/src/panic.rs new file mode 100644 index 00000000..f8d58a9e --- /dev/null +++ b/kernel/src/panic.rs @@ -0,0 +1,32 @@ +// use backtrace::backtrace; +use core::panic::PanicInfo; + +use polyhal::instruction::shutdown; + +#[inline] +fn hart_id() -> usize { + 0 +} + +// 程序遇到错误 +#[panic_handler] +fn panic_handler(info: &PanicInfo) -> ! { + if let Some(location) = info.location() { + println!( + "\x1b[1;31m[Core {}] [{}:{}]\x1b[0m", + hart_id(), + location.file(), + location.line(), + ); + } + println!( + "\x1b[1;31m[Core {}] panic: '{}'\x1b[0m", + hart_id(), + info.message().unwrap() + ); + // backtrace(); + println!("!TEST FINISH!"); + // loop {} + + shutdown(); +} diff --git a/kernel/src/socket.rs b/kernel/src/socket.rs new file mode 100644 index 00000000..55dd21fa --- /dev/null +++ b/kernel/src/socket.rs @@ -0,0 +1,209 @@ +use core::{cmp, net::SocketAddrV4}; + +use alloc::{sync::Arc, vec::Vec}; +use fs::INodeInterface; +use lose_net_stack::net_trait::SocketInterface; +use polyhal::debug_console::DebugConsole; +use sync::Mutex; +use vfscore::{Metadata, PollEvent, VfsResult}; + +use crate::syscall::NET_SERVER; + +#[derive(Clone, Copy, PartialEq, Debug)] +#[allow(dead_code)] +#[allow(clippy::upper_case_acronyms)] +pub enum NetType { + STEAM, + DGRAME, + RAW, +} + +impl NetType { + pub fn from_usize(value: usize) -> Option { + match value { + 1 => Some(Self::STEAM), + 2 => Some(Self::DGRAME), + _ => None, + } + } +} + +#[derive(Clone)] +pub struct SocketOptions { + pub wsize: usize, + pub rsize: usize, +} + +#[allow(dead_code)] +pub struct Socket { + pub domain: usize, + pub net_type: NetType, + pub inner: Arc, + pub options: Mutex, + pub buf: Mutex>, +} + +unsafe impl Sync for Socket {} +unsafe impl Send for Socket {} + +impl Drop for Socket { + fn drop(&mut self) { + log::debug!("strong count: {}", Arc::strong_count(&self.inner)); + // TIPS: the socke table map will consume a strong reference. + if !self.inner.is_closed().unwrap() + && (Arc::strong_count(&self.inner) == 2 || Arc::strong_count(&self.inner) == 1) + { + log::info!("drop socket"); + // self.inner.close().expect("cant close socket when droping socket in os."); + let _ = self.inner.close(); + } + // self.inner.close(); + } +} + +impl Socket { + pub fn new(domain: usize, net_type: NetType) -> Arc { + let inner: Arc = match net_type { + NetType::STEAM => NET_SERVER.blank_tcp(), + NetType::DGRAME => NET_SERVER.blank_udp(), + NetType::RAW => { + panic!("can't create raw socket") + } + }; + Arc::new(Self { + domain, + net_type, + inner, + options: Mutex::new(SocketOptions { wsize: 0, rsize: 0 }), + buf: Mutex::new(vec![]), + }) + } + + pub fn recv_from(&self) -> VfsResult<(Vec, SocketAddrV4)> { + log::warn!("try to recv data from {}", self.inner.get_local().unwrap()); + match self.inner.recv_from() { + Ok((data, remote)) => Ok((data, remote)), + Err(_err) => Err(vfscore::VfsError::Blocking), + } + } + + pub fn new_with_inner( + domain: usize, + net_type: NetType, + inner: Arc, + ) -> Arc { + Arc::new(Self { + domain, + net_type, + inner, + options: Mutex::new(SocketOptions { wsize: 0, rsize: 0 }), + buf: Mutex::new(vec![]), + }) + } + + pub fn reuse(&self, port: u16) -> Self { + // NET_SERVER.get_tcp(port) + match self.inner.get_protocol().unwrap() { + lose_net_stack::connection::SocketType::TCP => { + if let Some(socket_inner) = NET_SERVER.get_tcp(&port) { + Self { + domain: self.domain, + net_type: self.net_type, + inner: socket_inner, + options: Mutex::new(self.options.lock().clone()), + buf: Mutex::new(vec![]), + } + } else { + unreachable!("can't reusetcp in blank tcp") + } + } + lose_net_stack::connection::SocketType::UDP => { + if let Some(socket_inner) = NET_SERVER.get_udp(&port) { + Self { + domain: self.domain, + net_type: self.net_type, + inner: socket_inner, + options: Mutex::new(self.options.lock().clone()), + buf: Mutex::new(vec![]), + } + } else { + unreachable!("can't reusetcp in blank udp") + } + } + lose_net_stack::connection::SocketType::RAW => todo!(), + } + } +} + +impl INodeInterface for Socket { + fn metadata(&self) -> VfsResult { + Ok(Metadata { + filename: "", + inode: 0, + file_type: vfscore::FileType::Socket, + size: 0, + childrens: 0, + }) + } + + fn readat(&self, _offset: usize, buffer: &mut [u8]) -> VfsResult { + let mut data = self.buf.lock().clone(); + // let rlen; + // if buf.len() > 0 { + // rlen = cmp::min(buf.len(), buffer.len()); + // let + // } else { + // rlen = cmp::min(data.len(), buffer.len()); + // buffer[..rlen].copy_from_slice(&data[..rlen]); + // self.options.lock().rsize += rlen; + // if rlen < data.len() { + + // } + // } + // Ok(rlen) + if data.is_empty() { + match self.inner.recv_from() { + Ok((recv_data, _)) => { + data = recv_data; + } + Err(_err) => return Err(vfscore::VfsError::Blocking), + } + } + let rlen = cmp::min(data.len(), buffer.len()); + buffer[..rlen].copy_from_slice(&data[..rlen]); + self.options.lock().rsize += rlen; + if buffer.len() == 1 { + DebugConsole::putchar(buffer[0]); + } + if rlen < data.len() { + *self.buf.lock() = data[rlen..].to_vec(); + } else { + self.buf.lock().clear(); + } + Ok(rlen) + } + + fn writeat(&self, _offset: usize, buffer: &[u8]) -> VfsResult { + match self.inner.sendto(buffer, None) { + Ok(len) => { + self.options.lock().wsize += len; + Ok(len) + } + Err(_err) => Err(vfscore::VfsError::NotWriteable), + } + } + + fn poll(&self, events: PollEvent) -> VfsResult { + let mut res = PollEvent::NONE; + if events.contains(PollEvent::POLLOUT) + && !self.inner.is_closed().unwrap() + && self.inner.get_remote().is_ok() + { + res |= PollEvent::POLLOUT; + } + if self.inner.readable().unwrap() && events.contains(PollEvent::POLLIN) { + res |= PollEvent::POLLIN; + } + Ok(res) + } +} diff --git a/kernel/src/syscall/consts.rs b/kernel/src/syscall/consts.rs new file mode 100644 index 00000000..06ec0c66 --- /dev/null +++ b/kernel/src/syscall/consts.rs @@ -0,0 +1,936 @@ +//! allow dead code in the file +#![allow(dead_code)] +#![allow(clippy::upper_case_acronyms)] + +use core::fmt::{Debug, Display}; +use core::marker::PhantomData; + +use bitflags::bitflags; +use cfg_if::cfg_if; +use fs::VfsError; +use hal::TimeVal; +use num_derive::FromPrimitive; +use polyhal::addr::VirtAddr; +use polyhal::trapframe::TrapFrame; +use polyhal::MappingFlags; +use signal::SigProcMask; + +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum LinuxError { + /// Operation not permitted + EPERM = 1, + /// No such file or directory + ENOENT = 2, + /// No such process + ESRCH = 3, + /// Interrupted system call + EINTR = 4, + /// I/O error + EIO = 5, + /// No such device or address + ENXIO = 6, + /// Argument list too long + E2BIG = 7, + /// Exec format error + ENOEXEC = 8, + /// Bad file number + EBADF = 9, + /// No child processes + ECHILD = 10, + /// Try again + EAGAIN = 11, + /// Out of memory + ENOMEM = 12, + /// Permission denied + EACCES = 13, + /// Bad address + EFAULT = 14, + /// Block device required + ENOTBLK = 15, + /// Device or resource busy + EBUSY = 16, + /// File exists + EEXIST = 17, + /// Cross-device link + EXDEV = 18, + /// No such device + ENODEV = 19, + /// Not a directory + ENOTDIR = 20, + /// Is a directory + EISDIR = 21, + /// Invalid argument + EINVAL = 22, + /// File table overflow + ENFILE = 23, + /// Too many open files + EMFILE = 24, + /// Not a typewriter + ENOTTY = 25, + /// Text file busy + ETXTBSY = 26, + /// File too large + EFBIG = 27, + /// No space left on device + ENOSPC = 28, + /// Illegal seek + ESPIPE = 29, + /// Read-only file system + EROFS = 30, + /// Too many links + EMLINK = 31, + /// Broken pipe + EPIPE = 32, + /// Math argument out of domain of func + EDOM = 33, + /// Math result not representable + ERANGE = 34, + /// Resource deadlock would occur + EDEADLK = 35, + /// File name too long + ENAMETOOLONG = 36, + /// No record locks available + ENOLCK = 37, + /// Invalid system call number + ENOSYS = 38, + /// Directory not empty + ENOTEMPTY = 39, + /// Address family not supported + EAFNOSUPPORT = 97, + /// Transport endpoint is not connected + ENOTCONN = 107, + /// Connection time out + ETIMEDOUT = 100, + /// Connection refused + ECONNREFUSED = 111, + /// Aleady used + EALREADY = 114, +} + +impl LinuxError { + pub const fn as_str(&self) -> &'static str { + use self::LinuxError::*; + match self { + EPERM => "Operation not permitted", + ENOENT => "No such file or directory", + ESRCH => "No such process", + EINTR => "Interrupted system call", + EIO => "I/O error", + ENXIO => "No such device or address", + E2BIG => "Argument list too long", + ENOEXEC => "Exec format error", + EBADF => "Bad file number", + ECHILD => "No child processes", + EAGAIN => "Try again", + ENOMEM => "Out of memory", + EACCES => "Permission denied", + EFAULT => "Bad address", + ENOTBLK => "Block device required", + EBUSY => "Device or resource busy", + EEXIST => "File exists", + EXDEV => "Cross-device link", + ENODEV => "No such device", + ENOTDIR => "Not a directory", + EISDIR => "Is a directory", + EINVAL => "Invalid argument", + ENFILE => "File table overflow", + EMFILE => "Too many open files", + ENOTTY => "Not a typewriter", + ETXTBSY => "Text file busy", + EFBIG => "File too large", + ENOSPC => "No space left on device", + ESPIPE => "Illegal seek", + EROFS => "Read-only file system", + EMLINK => "Too many links", + EPIPE => "Broken pipe", + EDOM => "Math argument out of domain of func", + ERANGE => "Math result not representable", + EDEADLK => "Resource deadlock would occur", + ENAMETOOLONG => "File name too long", + ENOLCK => "No record locks available", + ENOSYS => "Invalid system call number", + ENOTEMPTY => "Directory not empty", + EAFNOSUPPORT => "Address family not supported", + ENOTCONN => "Transport endpoint is not connected", + ETIMEDOUT => "Connection time out", + ECONNREFUSED => "Connection refused", + EALREADY => "Port already used", + } + } + + pub const fn code(self) -> isize { + self as isize + } +} + +pub fn from_vfs(vfs_error: VfsError) -> LinuxError { + match vfs_error { + VfsError::NotLinkFile => LinuxError::EBADF, + VfsError::NotDir => LinuxError::ENOTDIR, + VfsError::NotFile => LinuxError::EBADF, + VfsError::NotSupported => LinuxError::EPERM, + VfsError::FileNotFound => LinuxError::ENOENT, + VfsError::AlreadyExists => LinuxError::EEXIST, + VfsError::InvalidData => LinuxError::EIO, + VfsError::DirectoryNotEmpty => LinuxError::ENOTEMPTY, + VfsError::InvalidInput => LinuxError::EINVAL, + VfsError::StorageFull => LinuxError::EIO, + VfsError::UnexpectedEof => LinuxError::EIO, + VfsError::WriteZero => LinuxError::EIO, + VfsError::Io => LinuxError::EIO, + VfsError::Blocking => LinuxError::EAGAIN, + VfsError::NoMountedPoint => LinuxError::ENOENT, + VfsError::NotAPipe => LinuxError::EPIPE, + VfsError::NotWriteable => LinuxError::EBADF, + } +} + +// 中断调用列表 +cfg_if::cfg_if! { + if #[cfg(any(target_arch = "riscv64", target_arch = "aarch64", target_arch = "loongarch64"))] { + pub const SYS_GETCWD: usize = 17; + pub const SYS_EPOLL_CREATE: usize = 20; + pub const SYS_EPOLL_CTL: usize = 21; + pub const SYS_EPOLL_WAIT: usize = 22; + pub const SYS_DUP: usize = 23; + pub const SYS_DUP3: usize = 24; + pub const SYS_FCNTL: usize = 25; + pub const SYS_IOCTL: usize = 29; + pub const SYS_MKDIRAT: usize = 34; + pub const SYS_UNLINKAT: usize = 35; + pub const SYS_UMOUNT2: usize = 39; + pub const SYS_MOUNT: usize = 40; + pub const SYS_STATFS: usize = 43; + pub const SYS_FTRUNCATE: usize = 46; + pub const SYS_FACCESSAT: usize = 48; + pub const SYS_CHDIR: usize = 49; + pub const SYS_OPENAT: usize = 56; + pub const SYS_CLOSE: usize = 57; + pub const SYS_PIPE2: usize = 59; + pub const SYS_GETDENTS: usize = 61; + pub const SYS_LSEEK: usize = 62; + pub const SYS_READ: usize = 63; + pub const SYS_WRITE: usize = 64; + pub const SYS_READV: usize = 65; + pub const SYS_WRITEV: usize = 66; + pub const SYS_PREAD: usize = 67; + pub const SYS_PWRITE: usize = 68; + pub const SYS_SENDFILE: usize = 71; + pub const SYS_PSELECT: usize = 72; + pub const SYS_PPOLL: usize = 73; + pub const SYS_READLINKAT: usize = 78; + pub const SYS_FSTATAT: usize = 79; + pub const SYS_FSTAT: usize = 80; + pub const SYS_FSYNC: usize = 82; + pub const SYS_UTIMEAT: usize = 88; + pub const SYS_EXIT: usize = 93; + pub const SYS_EXIT_GROUP: usize = 94; + pub const SYS_SET_TID_ADDRESS: usize = 96; + pub const SYS_FUTEX: usize = 98; + pub const SYS_SET_ROBUST_LIST: usize = 99; + pub const SYS_GET_ROBUST_LIST: usize = 100; + pub const SYS_NANOSLEEP: usize = 101; + pub const SYS_SETITIMER: usize = 103; + pub const SYS_GETTIME: usize = 113; + pub const SYS_CLOCK_GETRES: usize = 114; + pub const SYS_CLOCK_NANOSLEEP: usize = 115; + pub const SYS_KLOGCTL: usize = 116; + pub const SYS_SCHED_SETSCHEDULER: usize = 119; + pub const SYS_SCHED_GETSCHEDULER: usize = 120; + pub const SYS_SCHED_GETPARAM: usize = 121; + pub const SYS_SCHED_SETAFFINITY: usize = 122; + pub const SYS_SCHED_GETAFFINITY: usize = 123; + pub const SYS_SCHED_YIELD: usize = 124; + pub const SYS_KILL: usize = 129; + pub const SYS_TKILL: usize = 130; + pub const SYS_TGKILL: usize = 131; + pub const SYS_SIGSUSPEND: usize = 133; + pub const SYS_SIGACTION: usize = 134; + pub const SYS_SIGPROCMASK: usize = 135; + pub const SYS_SIGTIMEDWAIT: usize = 137; + pub const SYS_SIGRETURN: usize = 139; + pub const SYS_TIMES: usize = 153; + pub const SYS_SETPGID: usize = 154; + pub const SYS_GETPGID: usize = 155; + pub const SYS_SETSID: usize = 157; + pub const SYS_SETGROUPS: usize = 159; + pub const SYS_UNAME: usize = 160; + pub const SYS_GETRUSAGE: usize = 165; + pub const SYS_GETTIMEOFDAY: usize = 169; + pub const SYS_GETPID: usize = 172; + pub const SYS_GETPPID: usize = 173; + pub const SYS_GETUID: usize = 174; + pub const SYS_GETEUID: usize = 175; + pub const SYS_GETGID: usize = 176; + pub const SYS_GETEGID: usize = 177; + pub const SYS_GETTID: usize = 178; + pub const SYS_SYSINFO: usize = 179; + pub const SYS_SHMGET: usize = 194; + pub const SYS_SHMCTL: usize = 195; + pub const SYS_SHMAT: usize = 196; + pub const SYS_SOCKET: usize = 198; + pub const SYS_SOCKETPAIR: usize = 199; + pub const SYS_BIND: usize = 200; + pub const SYS_LISTEN: usize = 201; + pub const SYS_ACCEPT: usize = 202; + pub const SYS_CONNECT: usize = 203; + pub const SYS_GETSOCKNAME: usize = 204; + pub const SYS_GETPEERNAME: usize = 205; + pub const SYS_SENDTO: usize = 206; + pub const SYS_RECVFROM: usize = 207; + pub const SYS_SETSOCKOPT: usize = 208; + pub const SYS_GETSOCKOPT: usize = 209; + pub const SYS_SHUTDOWN: usize = 210; + pub const SYS_BRK: usize = 214; + pub const SYS_CLONE: usize = 220; + pub const SYS_EXECVE: usize = 221; + pub const SYS_MMAP: usize = 222; + pub const SYS_MPROTECT: usize = 226; + pub const SYS_MSYNC: usize = 227; + pub const SYS_MUNMAP: usize = 215; + pub const SYS_ACCEPT4: usize = 242; + pub const SYS_WAIT4: usize = 260; + pub const SYS_PRLIMIT64: usize = 261; + pub const SYS_RENAMEAT2: usize = 276; + pub const SYS_GETRANDOM: usize = 278; + pub const SYS_COPY_FILE_RANGE: usize = 285; + pub const SYS_FACCESSAT2: usize = 439; + } else if #[cfg(target_arch = "x86_64")] { + pub const SYS_OPEN: usize = 2; + pub const SYS_GETCWD: usize = 79; + pub const SYS_EPOLL_CREATE: usize = 213; + pub const SYS_EPOLL_CTL: usize = 233; + pub const SYS_EPOLL_WAIT: usize = 232; + pub const SYS_DUP: usize = 32; + pub const SYS_DUP2: usize = 33; + pub const SYS_FORK: usize = 57; + pub const SYS_DUP3: usize = 292; + pub const SYS_FCNTL: usize = 72; + pub const SYS_IOCTL: usize = 16; + pub const SYS_MKDIR: usize = 83; + pub const SYS_MKDIRAT: usize = 258; + pub const SYS_UNLINK: usize = 87; + pub const SYS_STAT: usize = 4; + pub const SYS_LSTAT: usize = 6; + pub const SYS_POLL: usize = 7; + pub const SYS_UNLINKAT: usize = 263; + pub const SYS_UMOUNT2: usize = 166; + pub const SYS_MOUNT: usize = 165; + pub const SYS_STATFS: usize = 137; + pub const SYS_FTRUNCATE: usize = 77; + pub const SYS_FACCESSAT: usize = 269; + pub const SYS_CHDIR: usize = 80; + pub const SYS_OPENAT: usize = 257; + pub const SYS_CLOSE: usize = 3; + pub const SYS_PIPE2: usize = 293; + pub const SYS_PIPE: usize = 22; + pub const SYS_GETDENTS: usize = 217; + pub const SYS_LSEEK: usize = 8; + pub const SYS_READ: usize = 0; + pub const SYS_WRITE: usize = 1; + pub const SYS_READV: usize = 19; + pub const SYS_WRITEV: usize = 20; + pub const SYS_PREAD: usize = 17; + pub const SYS_PWRITE: usize = 18; + pub const SYS_SENDFILE: usize = 40; + pub const SYS_SELECT: usize = 23; + pub const SYS_SETGROUPS: usize = 116; + pub const SYS_PSELECT: usize = 270; + pub const SYS_PPOLL: usize = 271; + pub const SYS_READLINK: usize = 89; + pub const SYS_READLINKAT: usize = 267; + pub const SYS_FSTATAT: usize = 262; + pub const SYS_FSTAT: usize = 5; + pub const SYS_FSYNC: usize = 74; + pub const SYS_UTIMEAT: usize = 280; + pub const SYS_EXIT: usize = 60; + pub const SYS_EXIT_GROUP: usize = 231; + pub const SYS_SET_TID_ADDRESS: usize = 218; + pub const SYS_FUTEX: usize = 202; + pub const SYS_SET_ROBUST_LIST: usize = 273; + pub const SYS_GET_ROBUST_LIST: usize = 274; + pub const SYS_NANOSLEEP: usize = 35; + pub const SYS_SETITIMER: usize = 38; + pub const SYS_GETTIME: usize = 228; + pub const SYS_CLOCK_GETRES: usize = 229; + pub const SYS_CLOCK_NANOSLEEP: usize = 230; + pub const SYS_KLOGCTL: usize = 103; + pub const SYS_SCHED_SETSCHEDULER: usize = 144; + pub const SYS_SCHED_GETSCHEDULER: usize = 145; + pub const SYS_SCHED_GETPARAM: usize = 143; + pub const SYS_SCHED_SETAFFINITY: usize = 203; + pub const SYS_SCHED_GETAFFINITY: usize = 204; + pub const SYS_SCHED_YIELD: usize = 24; + pub const SYS_KILL: usize = 62; + pub const SYS_TKILL: usize = 200; + pub const SYS_TGKILL: usize = 234; + pub const SYS_SIGSUSPEND: usize = 130; + pub const SYS_SIGACTION: usize = 13; + pub const SYS_SIGPROCMASK: usize = 14; + pub const SYS_SIGTIMEDWAIT: usize = 128; + pub const SYS_SIGRETURN: usize = 15; + pub const SYS_TIMES: usize = 100; + pub const SYS_SETPGID: usize = 109; + pub const SYS_GETPGID: usize = 121; + pub const SYS_SETSID: usize = 112; + pub const SYS_ARCH_PRCTL: usize = 158; + pub const SYS_UNAME: usize = 63; + pub const SYS_GETRUSAGE: usize = 98; + pub const SYS_GETTIMEOFDAY: usize = 96; + pub const SYS_GETPID: usize = 39; + pub const SYS_GETPPID: usize = 110; + pub const SYS_GETUID: usize = 102; + pub const SYS_GETEUID: usize = 107; + pub const SYS_GETGID: usize = 104; + pub const SYS_GETEGID: usize = 108; + pub const SYS_GETTID: usize = 186; + pub const SYS_SYSINFO: usize = 99; + pub const SYS_SHMGET: usize = 29; + pub const SYS_SHMCTL: usize = 31; + pub const SYS_SHMAT: usize = 30; + pub const SYS_SOCKET: usize = 41; + pub const SYS_SOCKETPAIR: usize = 53; + pub const SYS_BIND: usize = 49; + pub const SYS_LISTEN: usize = 50; + pub const SYS_ACCEPT: usize = 43; + pub const SYS_CONNECT: usize = 42; + pub const SYS_GETSOCKNAME: usize = 51; + pub const SYS_GETPEERNAME: usize = 52; + pub const SYS_SENDTO: usize = 44; + pub const SYS_RECVFROM: usize = 45; + pub const SYS_SETSOCKOPT: usize = 54; + pub const SYS_GETSOCKOPT: usize = 55; + pub const SYS_SHUTDOWN: usize = 48; + pub const SYS_BRK: usize = 12; + pub const SYS_CLONE: usize = 56; + pub const SYS_EXECVE: usize = 59; + pub const SYS_MMAP: usize = 9; + pub const SYS_MPROTECT: usize = 10; + pub const SYS_MSYNC: usize = 26; + pub const SYS_MUNMAP: usize = 11; + pub const SYS_ACCEPT4: usize = 288; + pub const SYS_WAIT4: usize = 61; + pub const SYS_PRLIMIT64: usize = 302; + pub const SYS_RENAMEAT2: usize = 316; + pub const SYS_GETRANDOM: usize = 318; + pub const SYS_COPY_FILE_RANGE: usize = 326; + pub const SYS_FACCESSAT2: usize = 439; + } + +} + +pub const AT_CWD: usize = -100_isize as usize; + +pub struct UTSname { + pub sysname: [u8; 65], + pub nodename: [u8; 65], + pub release: [u8; 65], + pub version: [u8; 65], + pub machine: [u8; 65], + pub domainname: [u8; 65], +} + +bitflags! { + // MAP Flags + #[derive(Debug)] + pub struct MapFlags: u32 { + const MAP_SHARED = 0x01; + const MAP_PRIVATE = 0x02; + const MAP_SHARED_VALIDATE = 0x03; + const MAP_TYPE = 0x0f; + const MAP_FIXED = 0x10; + const MAP_ANONYMOUS = 0x20; + const MAP_NORESERVE = 0x4000; + const MAP_GROWSDOWN = 0x0100; + const MAP_DENYWRITE = 0x0800; + const MAP_EXECUTABLE = 0x1000; + const MAP_LOCKED = 0x2000; + const MAP_POPULATE = 0x8000; + const MAP_NONBLOCK = 0x10000; + const MAP_STACK = 0x20000; + const MAP_HUGETLB = 0x40000; + const MAP_SYNC = 0x80000; + const MAP_FIXED_NOREPLACE = 0x100000; + const MAP_FILE = 0; + } + + #[derive(Debug, Clone, Copy)] + pub struct MmapProt: u32 { + const PROT_READ = 1 << 0; + const PROT_WRITE = 1 << 1; + const PROT_EXEC = 1 << 2; + } + + #[derive(Debug)] + pub struct MSyncFlags: u32 { + const ASYNC = 1 << 0; + const INVALIDATE = 1 << 1; + const SYNC = 1 << 2; + } + + #[derive(Debug)] + pub struct ProtFlags: u32 { + const PROT_NONE = 0; + const PROT_READ = 1; + const PROT_WRITE = 2; + const PROT_EXEC = 4; + } + + #[derive(Debug)] + pub struct CloneFlags: usize { + const CSIGNAL = 0x000000ff; + const CLONE_VM = 0x00000100; + const CLONE_FS = 0x00000200; + const CLONE_FILES = 0x00000400; + const CLONE_SIGHAND = 0x00000800; + const CLONE_PIDFD = 0x00001000; + const CLONE_PTRACE = 0x00002000; + const CLONE_VFORK = 0x00004000; + const CLONE_PARENT = 0x00008000; + const CLONE_THREAD = 0x00010000; + const CLONE_NEWNS = 0x00020000; + const CLONE_SYSVSEM = 0x00040000; + const CLONE_SETTLS = 0x00080000; + const CLONE_PARENT_SETTID = 0x00100000; + const CLONE_CHILD_CLEARTID = 0x00200000; + const CLONE_DETACHED = 0x00400000; + const CLONE_UNTRACED = 0x00800000; + const CLONE_CHILD_SETTID = 0x01000000; + const CLONE_NEWCGROUP = 0x02000000; + const CLONE_NEWUTS = 0x04000000; + const CLONE_NEWIPC = 0x08000000; + const CLONE_NEWUSER = 0x10000000; + const CLONE_NEWPID = 0x20000000; + const CLONE_NEWNET = 0x40000000; + const CLONE_IO = 0x80000000; + } +} + +impl From for MappingFlags { + fn from(val: MmapProt) -> Self { + let mut res = MappingFlags::empty(); + if val.contains(MmapProt::PROT_READ) { + res |= MappingFlags::R; + } + if val.contains(MmapProt::PROT_WRITE) { + res |= MappingFlags::W; + } + if val.contains(MmapProt::PROT_EXEC) { + res |= MappingFlags::X; + } + res + } +} + +#[derive(Debug, FromPrimitive)] +#[repr(usize)] +pub enum FutexFlags { + Wait = 0, + Wake = 1, + Fd = 2, + Requeue = 3, + CmpRequeue = 4, + WakeOp = 5, + LockPi = 6, + UnlockPi = 7, + TrylockPi = 8, + WaitBitset = 9, +} + +#[repr(C)] +#[derive(Clone)] +pub struct IoVec { + pub base: usize, + pub len: usize, +} + +pub mod elf { + pub const AT_NULL: usize = 0; + pub const AT_IGNORE: usize = 1; + pub const AT_EXECFD: usize = 2; + pub const AT_PHDR: usize = 3; + pub const AT_PHENT: usize = 4; + pub const AT_PHNUM: usize = 5; + pub const AT_PAGESZ: usize = 6; + pub const AT_BASE: usize = 7; + pub const AT_FLAGS: usize = 8; + pub const AT_ENTRY: usize = 9; + pub const AT_NOTELF: usize = 10; + pub const AT_UID: usize = 11; + pub const AT_EUID: usize = 12; + pub const AT_GID: usize = 13; + pub const AT_EGID: usize = 14; + pub const AT_PLATFORM: usize = 15; + pub const AT_HWCAP: usize = 16; + pub const AT_CLKTCK: usize = 17; + pub const AT_FPUCW: usize = 18; + pub const AT_DCACHEBSIZE: usize = 19; + pub const AT_ICACHEBSIZE: usize = 20; + pub const AT_UCACHEBSIZE: usize = 21; + pub const AT_IGNOREPPC: usize = 22; + pub const AT_SECURE: usize = 23; + pub const AT_BASE_PLATFORM: usize = 24; + pub const AT_RANDOM: usize = 25; + pub const AT_HWCAP2: usize = 26; + + pub const AT_EXECFN: usize = 31; + pub const AT_SYSINFO: usize = 32; + pub const AT_SYSINFO_EHDR: usize = 33; +} + +#[allow(unused)] +pub mod fcntl_cmd { + /// dup + pub const DUPFD: usize = 0; + /// get close_on_exec + pub const GETFD: usize = 1; + /// set/clear close_on_exec + pub const SETFD: usize = 2; + /// get file->f_flags + pub const GETFL: usize = 3; + /// set file->f_flags + pub const SETFL: usize = 4; + /// Get record locking info. + pub const GETLK: usize = 5; + /// Set record locking info (non-blocking). + pub const SETLK: usize = 6; + /// Set record locking info (blocking). + pub const SETLKW: usize = 7; + /// like F_DUPFD, but additionally set the close-on-exec flag + pub const DUPFD_CLOEXEC: usize = 0x406; +} + +#[repr(u32)] +#[derive(Debug, Clone, PartialEq, FromPrimitive)] +pub enum FcntlCmd { + /// dup + DUPFD = 0, + /// get close_on_exec + GETFD = 1, + /// set/clear close_on_exec + SETFD = 2, + /// get file->f_flags + GETFL = 3, + /// set file->f_flags + SETFL = 4, + /// Get record locking info. + GETLK = 5, + /// Set record locking info (non-blocking). + SETLK = 6, + /// Set record locking info (blocking). + SETLKW = 7, + /// like F_DUPFD, but additionally set the close-on-exec flag + DUPFDCLOEXEC = 0x406, +} + +#[repr(usize)] +#[derive(Debug, Clone, FromPrimitive)] +#[allow(non_camel_case_types)] +pub enum ArchPrctlCode { + ARCH_SET_GS = 0x1001, + ARCH_SET_FS = 0x1002, + ARCH_GET_FS = 0x1003, + ARCH_GET_GS = 0x1004, +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Rlimit { + pub curr: usize, + pub max: usize, +} + +pub const RLIMIT_NOFILE: usize = 7; + +bitflags! { + #[derive(Debug, Clone)] + pub struct SignalStackFlags : u32 { + const ONSTACK = 1; + const DISABLE = 2; + const AUTODISARM = 0x80000000; + } +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct SignalStack { + pub sp: usize, + pub flags: SignalStackFlags, + pub size: usize, +} + +cfg_if! { + if #[cfg(target_arch = "x86_64")] { + #[repr(C)] + #[derive(Debug, Clone)] + pub struct SignalUserContext { + pub flags: usize, // 0 + pub link: usize, // 1 + pub stack: SignalStack, // 2 + pub gregs: [usize; 32], + pub sig_mask: SigProcMask, // sigmask + pub _pad: [u64; 16], // sigmask extend + pub __fpregs_mem: [u64; 64] + } + + impl SignalUserContext { + pub fn pc(&self) -> usize { + self.gregs[16] + } + + pub fn set_pc(&mut self, v: usize) { + self.gregs[16] = v; + } + + pub fn store_ctx(&mut self, ctx: &TrapFrame) { + self.gregs[0] = ctx.r8; + self.gregs[1] = ctx.r9; + self.gregs[2] = ctx.r10; + self.gregs[3] = ctx.r11; + self.gregs[4] = ctx.r12; + self.gregs[5] = ctx.r13; + self.gregs[6] = ctx.r14; + self.gregs[7] = ctx.r15; + self.gregs[8] = ctx.rdi; + self.gregs[9] = ctx.rsi; + self.gregs[10] = ctx.rbp; + self.gregs[11] = ctx.rbx; + self.gregs[12] = ctx.rdx; + self.gregs[13] = ctx.rax; + self.gregs[14] = ctx.rcx; + self.gregs[15] = ctx.rsp; + self.gregs[16] = ctx.rip; + } + + pub fn restore_ctx(&self, ctx: &mut TrapFrame) { + ctx.r8 = self.gregs[0]; + ctx.r9 = self.gregs[1]; + ctx.r10 = self.gregs[2]; + ctx.r11 = self.gregs[3]; + ctx.r12 = self.gregs[4]; + ctx.r13 = self.gregs[5]; + ctx.r14 = self.gregs[6]; + ctx.r15 = self.gregs[7]; + ctx.rdi = self.gregs[8]; + ctx.rsi = self.gregs[9]; + ctx.rbp = self.gregs[10]; + ctx.rbx = self.gregs[11]; + ctx.rdx = self.gregs[12]; + ctx.rax = self.gregs[13]; + ctx.rcx = self.gregs[14]; + ctx.rsp = self.gregs[15]; + ctx.rip = self.gregs[16]; + } + } + } else if #[cfg(target_arch = "riscv64")] { + #[repr(C)] + #[derive(Debug, Clone)] + pub struct SignalUserContext { + pub flags: usize, // 0 + pub link: usize, // 1 + pub stack: SignalStack, // 2 + pub sig_mask: SigProcMask, // 5 + pub _pad: [u64; 16], // mask + // pub context: Context, // pc offset = 22 - 6=16 + pub gregs: [usize; 32], + pub fpstate: [usize; 66], + } + + impl SignalUserContext { + pub fn pc(&self) -> usize { + self.gregs[0] + } + + pub fn set_pc(&mut self, v: usize) { + self.gregs[0] = v; + } + + pub fn store_ctx(&mut self, ctx: &TrapFrame) { + self.gregs = ctx.x; + } + + pub fn restore_ctx(&self, ctx: &mut TrapFrame) { + ctx.x = self.gregs; + } + } + } else if #[cfg(target_arch = "aarch64")] { + #[repr(C)] + #[derive(Debug, Clone)] + pub struct SignalUserContext { + pub flags: usize, // 0 + pub link: usize, // 1 + pub stack: SignalStack, // 2 + pub sig_mask: SigProcMask, // 5 + pub _pad: [u64; 16], // mask + pub fault_address: usize, + pub regs: [usize; 31], + pub sp: usize, + pub pc: usize, + pub pstate: usize, + pub __reserved: usize, + } + + impl SignalUserContext { + pub fn pc(&self) -> usize { + self.pc + } + + pub fn set_pc(&mut self, v: usize) { + self.pc = v; + } + + pub fn store_ctx(&mut self, ctx: &TrapFrame) { + self.regs = ctx.regs; + } + + pub fn restore_ctx(&self, ctx: &mut TrapFrame) { + ctx.regs = self.regs; + } + } + } else if #[cfg(target_arch = "loongarch64")] { + #[repr(C)] + #[derive(Debug, Clone)] + pub struct SignalUserContext { + pub flags: usize, // 0 + pub link: usize, // 1 + pub stack: SignalStack, // 2 + pub sig_mask: SigProcMask, // 5 + pub _pad: [u64; 2], // mask + pub pc: usize, + pub gregs: [usize; 32], + pub gflags: u32, + pub fcsr: u32, + pub scr: [usize; 4], + pub fregs: [usize; 32], // _extcontext + pub _reserved: [usize; 512], + } + + impl SignalUserContext { + pub fn pc(&self) -> usize { + self.pc + } + + pub fn set_pc(&mut self, v: usize) { + self.pc = v; + } + + pub fn store_ctx(&mut self, ctx: &TrapFrame) { + self.gregs = ctx.regs; + } + + pub fn restore_ctx(&self, ctx: &mut TrapFrame) { + ctx.regs = self.gregs; + } + } + } +} + +#[repr(C)] +pub struct Rusage { + pub ru_utime: TimeVal, + pub ru_stime: TimeVal, + pub ru_maxrss: i64, + pub ru_ixrss: i64, + pub ru_idrss: i64, + pub ru_isrss: i64, + pub ru_minflt: i64, + pub ru_majflt: i64, + pub ru_nswap: i64, + pub ru_inblock: i64, + pub ru_oublock: i64, + pub ru_msgsnd: i64, + pub ru_msgrcv: i64, + pub ru_nsignals: i64, + pub ru_nvcsw: i64, + pub ru_nivcsw: i64, +} + +#[derive(Clone, Copy)] +pub struct UserRef { + addr: VirtAddr, + r#type: PhantomData, +} + +impl From for UserRef { + fn from(value: usize) -> Self { + Self { + addr: value.into(), + r#type: PhantomData, + } + } +} + +impl From for UserRef { + fn from(value: VirtAddr) -> Self { + Self { + addr: value, + r#type: PhantomData, + } + } +} + +impl From> for usize { + fn from(val: UserRef) -> Self { + val.addr.addr() + } +} + +impl UserRef { + #[inline] + pub fn addr(&self) -> usize { + self.addr.addr() + } + #[inline] + pub fn get_ref(&self) -> &'static T { + self.addr.get_ref::() + } + + #[inline] + pub fn get_mut(&self) -> &'static mut T { + self.addr.get_mut_ref::() + } + + #[inline] + pub fn slice_mut_with_len(&self, len: usize) -> &'static mut [T] { + self.addr.slice_mut_with_len(len) + } + + #[inline] + pub fn slice_until_valid(&self, is_valid: fn(T) -> bool) -> &'static mut [T] { + if self.addr.addr() == 0 { + return &mut []; + } + self.addr.slice_until(is_valid) + } + + #[inline] + pub fn get_cstr(&self) -> Result<&str, core::str::Utf8Error> { + self.addr.get_cstr().to_str() + } + + #[inline] + pub fn is_valid(&self) -> bool { + self.addr.addr() != 0 + } +} + +impl Display for UserRef { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "{}({:#x})", + core::any::type_name::(), + self.addr.addr() + )) + } +} + +impl Debug for UserRef { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "{}({:#x})", + core::any::type_name::(), + self.addr.addr() + )) + } +} diff --git a/kernel/src/syscall/fd.rs b/kernel/src/syscall/fd.rs new file mode 100644 index 00000000..321fd4da --- /dev/null +++ b/kernel/src/syscall/fd.rs @@ -0,0 +1,998 @@ +use alloc::string::String; +use core::cmp; +use fs::dentry::{dentry_open, DentryNode}; +use num_traits::FromPrimitive; +use vfscore::FileType; + +use alloc::sync::Arc; +use bit_field::BitArray; +use executor::yield_now; +use fs::pipe::create_pipe; +use fs::{OpenFlags, PollEvent, PollFd, SeekFrom, Stat, StatFS, StatMode, TimeSpec, UTIME_NOW}; +use log::debug; +use polyhal::addr::VirtAddr; + +use crate::epoll::{EpollEvent, EpollFile}; +use crate::syscall::consts::{from_vfs, FcntlCmd, IoVec, AT_CWD}; +use crate::syscall::func::timespc_now; +use crate::syscall::time::current_nsec; +use crate::tasks::{FileItem, UserTask}; +use crate::user::UserTaskContainer; + +use super::consts::{LinuxError, UserRef}; +use super::SysResult; + +pub fn to_node(task: &Arc, fd: usize, path: &str) -> Result, LinuxError> { + if !path.is_empty() && path.starts_with('/') { + return Ok(FileItem::root()); + } + const NEW_AT_CWD: u32 = AT_CWD as u32; + match fd as u32 { + NEW_AT_CWD => Ok(task.pcb.lock().curr_dir.clone()), + x => task.get_fd(x as _).ok_or(LinuxError::EBADF), + } +} + +impl UserTaskContainer { + pub async fn sys_dup(&self, fd: usize) -> SysResult { + debug!("sys_dup3 @ fd_src: {}", fd); + let fd_dst = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + self.sys_dup3(fd, fd_dst).await + } + + pub async fn sys_dup3(&self, fd_src: usize, fd_dst: usize) -> SysResult { + debug!("sys_dup3 @ fd_src: {}, fd_dst: {}", fd_src, fd_dst); + let file = self.task.get_fd(fd_src).ok_or(LinuxError::EBADF)?; + self.task.set_fd(fd_dst, file); + Ok(fd_dst) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_dup2(&self, fd_src: usize, fd_dst: usize) -> SysResult { + self.sys_dup3(fd_src, fd_dst).await + } + + pub async fn sys_read(&self, fd: usize, buf_ptr: UserRef, count: usize) -> SysResult { + debug!( + "[task {}] sys_read @ fd: {} buf_ptr: {:?} count: {}", + self.tid, fd as isize, buf_ptr, count + ); + let buffer = buf_ptr.slice_mut_with_len(count); + self.task + .get_fd(fd) + .ok_or(LinuxError::EBADF)? + .async_read(buffer) + .await + .map_err(from_vfs) + } + + pub async fn sys_write(&self, fd: usize, buf_ptr: VirtAddr, count: usize) -> SysResult { + debug!( + "[task {}] sys_write @ fd: {} buf_ptr: {:?} count: {}", + self.tid, fd as isize, buf_ptr, count + ); + let buffer = buf_ptr.slice_with_len(count); + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + // if let Ok(_) = file.get_bare_file().downcast_arc::() { + // yield_now().await; + // } + file.async_write(buffer).await.map_err(from_vfs) + } + + pub async fn sys_readv(&self, fd: usize, iov: UserRef, iocnt: usize) -> SysResult { + debug!("sys_readv @ fd: {}, iov: {}, iocnt: {}", fd, iov, iocnt); + + let mut rsize = 0; + + let iov = iov.slice_mut_with_len(iocnt); + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + + for io in iov { + let buffer = UserRef::::from(io.base).slice_mut_with_len(io.len); + rsize += file.read(buffer).map_err(from_vfs)?; + } + + Ok(rsize) + } + + pub async fn sys_writev(&self, fd: usize, iov: UserRef, iocnt: usize) -> SysResult { + debug!("sys_writev @ fd: {}, iov: {}, iocnt: {}", fd, iov, iocnt); + let mut wsize = 0; + + let iov = iov.slice_mut_with_len(iocnt); + + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + + for io in iov { + let buffer = UserRef::::from(io.base).slice_mut_with_len(io.len); + wsize += file.write(buffer).map_err(from_vfs)?; + } + + Ok(wsize) + } + + pub async fn sys_close(&self, fd: usize) -> SysResult { + debug!("[task {}] sys_close @ fd: {}", self.tid, fd as isize); + + self.task.clear_fd(fd); + Ok(0) + } + + pub async fn sys_mkdir_at(&self, dir_fd: usize, path: UserRef, mode: usize) -> SysResult { + let path = path.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!( + "sys_mkdir_at @ dir_fd: {}, path: {}, mode: {}", + dir_fd as isize, path, mode + ); + let dir = to_node(&self.task, dir_fd, path)?; + if path == "/" { + return Err(LinuxError::EEXIST); + } + + dir.dentry_open(path, OpenFlags::O_CREAT | OpenFlags::O_DIRECTORY) + .map_err(from_vfs)?; + // let path_str = rebuild_path(path); + // let paths: Vec<&str> = path_str.split("/").collect(); + // let mut pfile = dir.inner.clone(); + // for i in paths.into_iter().filter(|x| *x != "") { + // let f = pfile.open(i, OpenFlags::O_RDWR); + // if f.is_err() { + // pfile.mkdir(i).map_err(from_vfs)?; + // } else { + // pfile = f.unwrap(); + // } + // } + Ok(0) + } + + pub async fn sys_renameat2( + &self, + olddir_fd: usize, + oldpath: UserRef, + newdir_fd: usize, + newpath: UserRef, + flags: usize, + ) -> SysResult { + debug!( + "sys_renameat2 @ olddir_fd: {}, oldpath: {}, newdir_fd: {}, newpath: {}, flags: {}", + olddir_fd, oldpath, newdir_fd, newpath, flags + ); + + let old_path = oldpath.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let old_dir = to_node(&self.task, olddir_fd, old_path)?; + let old_file = old_dir + .dentry_open(old_path, OpenFlags::empty()) + .map_err(from_vfs)?; + + let old_file_type = old_file.metadata().map_err(from_vfs)?.file_type; + let new_path = newpath.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let new_dir = to_node(&self.task, newdir_fd, new_path)?; + if old_file_type == FileType::File { + let new_file = new_dir + .dentry_open(new_path, OpenFlags::O_CREAT) + .expect("can't find new file"); + // TODO: Check the file exists + let file_size = old_file.metadata().map_err(from_vfs)?.size; + let mut buffer = vec![0u8; file_size]; + old_file.read(&mut buffer).map_err(from_vfs)?; + new_file.write(&buffer).map_err(from_vfs)?; + new_file.truncate(buffer.len()).map_err(from_vfs)?; + } else if old_file_type == FileType::Directory { + new_dir.mkdir(new_path).map_err(from_vfs)?; + } else { + panic!("can't handle the file: {:?} now", old_file_type); + } + + Ok(0) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_mkdir(&self, path: UserRef, mode: usize) -> SysResult { + self.sys_mkdir_at(AT_CWD, path, mode).await + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_unlink(&self, path: UserRef) -> SysResult { + self.sys_unlinkat(AT_CWD, path, 0).await + } + + pub async fn sys_unlinkat(&self, dir_fd: usize, path: UserRef, flags: usize) -> SysResult { + let path = path.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!( + "sys_unlinkat @ dir_fd: {}, path: {}, flags: {}", + dir_fd as isize, path, flags + ); + let flags = OpenFlags::from_bits_truncate(flags); + let dir = to_node(&self.task, dir_fd, path)?; + let file = dir.dentry_open(path, flags).map_err(from_vfs)?; + + file.remove_self().map_err(from_vfs)?; + Ok(0) + } + + pub async fn sys_openat( + &self, + fd: usize, + filename: UserRef, + flags: usize, + mode: usize, + ) -> SysResult { + let flags = OpenFlags::from_bits_truncate(flags); + let filename = if filename.is_valid() { + filename.get_cstr().map_err(|_| LinuxError::EINVAL)? + } else { + "" + }; + debug!( + "sys_openat @ fd: {}, filename: {}, flags: {:?}, mode: {}", + fd as isize, filename, flags, mode + ); + let dir = to_node(&self.task, fd, filename)?; + let file = dir.dentry_open(filename, flags).map_err(from_vfs)?; + let fd = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + self.task.set_fd(fd, file); + debug!("sys_openat @ ret fd: {}", fd); + Ok(fd) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_open(&self, path: UserRef, flags: usize, mode: usize) -> SysResult { + // syscall_openat(axprocess::link::AT_FDCWD, path, flags, mode) + self.sys_openat(AT_CWD, path, flags, mode).await + } + + pub async fn sys_faccess_at( + &self, + fd: usize, + filename: UserRef, + mode: usize, + flags: usize, + ) -> SysResult { + let open_flags = OpenFlags::from_bits_truncate(flags); + let filename = if filename.is_valid() { + filename.get_cstr().map_err(|_| LinuxError::EINVAL)? + } else { + "" + }; + debug!( + "sys_accessat @ fd: {}, filename: {}, flags: {:?}, mode: {}", + fd as isize, filename, open_flags, mode + ); + let dir = to_node(&self.task, fd, filename)?; + let _node = + dentry_open(dir.dentry.clone().unwrap(), filename, open_flags).map_err(from_vfs)?; + Ok(0) + } + + pub async fn sys_fstat(&self, fd: usize, stat_ptr: UserRef) -> SysResult { + debug!("sys_fstat @ fd: {} stat_ptr: {}", fd, stat_ptr); + let stat_ref = stat_ptr.get_mut(); + + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + file.stat(stat_ref).map_err(from_vfs)?; + stat_ref.mode |= StatMode::OWNER_MASK; + if let Ok(metadata) = file.metadata() { + stat_ref.ino = metadata.filename.as_ptr() as _; + } + Ok(0) + } + + pub async fn sys_fstatat( + &self, + dir_fd: usize, + path_ptr: UserRef, + stat_ptr: UserRef, + ) -> SysResult { + debug!( + "sys_fstatat @ dir_fd: {}, path_ptr:{}, stat_ptr: {}", + dir_fd as isize, path_ptr, stat_ptr + ); + let path = path_ptr.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!( + "sys_fstatat @ dir_fd: {}, path:{}, stat_ptr: {}", + dir_fd as isize, path, stat_ptr + ); + let stat = stat_ptr.get_mut(); + + let dir = to_node(&self.task, dir_fd, path)?; + dentry_open(dir.dentry.clone().unwrap(), path, OpenFlags::NONE) + .map_err(from_vfs)? + .node + .stat(stat) + .map_err(from_vfs)?; + stat.mode |= StatMode::OWNER_MASK; + Ok(0) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_stat(&self, path: UserRef, stat_ptr: UserRef) -> SysResult { + self.sys_fstatat(AT_CWD, path, stat_ptr).await + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_lstat(&self, path: UserRef, stat_ptr: UserRef) -> SysResult { + self.sys_fstatat(AT_CWD, path, stat_ptr).await + } + + pub async fn sys_statfs( + &self, + filename_ptr: UserRef, + statfs_ptr: UserRef, + ) -> SysResult { + debug!( + "sys_statfs @ filename_ptr: {}, statfs_ptr: {}", + filename_ptr, statfs_ptr + ); + let path = filename_ptr.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let statfs = statfs_ptr.get_mut(); + FileItem::fs_open(path, OpenFlags::NONE) + .map_err(from_vfs)? + .statfs(statfs) + .map_err(from_vfs)?; + Ok(0) + } + + pub async fn sys_pipe2(&self, fds_ptr: UserRef, _unknown: usize) -> SysResult { + debug!("sys_pipe2 @ fds_ptr: {}, _unknown: {}", fds_ptr, _unknown); + let fds = fds_ptr.slice_mut_with_len(2); + + let (rx, tx) = create_pipe(); + let rx_fd = self.task.alloc_fd().ok_or(LinuxError::ENFILE)?; + self.task.set_fd(rx_fd, FileItem::new_dev(rx)); + fds[0] = rx_fd as u32; + + let tx_fd = self.task.alloc_fd().ok_or(LinuxError::ENFILE)?; + self.task.set_fd(tx_fd, FileItem::new_dev(tx)); + fds[1] = tx_fd as u32; + + debug!("sys_pipe2 ret: {} {}", rx_fd as u32, tx_fd as u32); + Ok(0) + } + + pub async fn sys_pread( + &self, + fd: usize, + ptr: UserRef, + len: usize, + offset: usize, + ) -> SysResult { + debug!( + "sys_pread @ fd: {}, ptr: {}, len: {}, offset: {}", + fd, ptr, len, offset + ); + let buffer = ptr.slice_mut_with_len(len); + + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + file.readat(offset, buffer).map_err(from_vfs) + } + + pub async fn sys_pwrite( + &self, + fd: usize, + buf_ptr: VirtAddr, + count: usize, + offset: usize, + ) -> SysResult { + debug!( + "sys_write @ fd: {} buf_ptr: {:?} count: {}", + fd as isize, buf_ptr, count + ); + let buffer = buf_ptr.slice_with_len(count); + self.task + .get_fd(fd) + .ok_or(LinuxError::EBADF)? + .writeat(offset, buffer) + .map_err(from_vfs) + } + + pub async fn sys_mount( + &self, + special: UserRef, + dir: UserRef, + fstype: UserRef, + flags: usize, + data: usize, + ) -> SysResult { + let special = special.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let dir = dir.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let fstype = fstype.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!( + "sys_mount @ special: {}, dir: {}, fstype: {}, flags: {}, data: {:#x}", + special, dir, fstype, flags, data + ); + + let dev_node = FileItem::fs_open(special, OpenFlags::NONE).map_err(from_vfs)?; + dev_node.mount(dir).map_err(from_vfs)?; + Ok(0) + } + + pub async fn sys_umount2(&self, special: UserRef, flags: usize) -> SysResult { + let special = special.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!("sys_umount @ special: {}, flags: {}", special, flags); + match special.starts_with("/dev") { + true => { + todo!("unmount dev"); + // let dev = dentry_open(dentry_root(), special, OpenFlags::NONE).map_err(from_vfs)?; + // dev.node.umount().map_err(from_vfs)?; + } + false => { + DentryNode::unmount(String::from(special)).map_err(from_vfs)?; + } + }; + + Ok(0) + } + + pub async fn sys_getdents64(&self, fd: usize, buf_ptr: UserRef, len: usize) -> SysResult { + debug!( + "[task {}] sys_getdents64 @ fd: {}, buf_ptr: {}, len: {}", + self.tid, fd, buf_ptr, len + ); + + let file = self.task.get_fd(fd).unwrap(); + + let buffer = buf_ptr.slice_mut_with_len(len); + file.getdents(buffer).map_err(from_vfs) + } + + pub fn sys_lseek(&self, fd: usize, offset: usize, whence: usize) -> SysResult { + debug!( + "[task {}] sys_lseek @ fd {}, offset: {}, whench: {}", + self.tid, fd, offset as isize, whence + ); + + self.task + .get_fd(fd) + .ok_or(LinuxError::EBADF)? + .seek(match whence { + 0 => SeekFrom::SET(offset), + 1 => SeekFrom::CURRENT(offset as isize), + 2 => SeekFrom::END(offset as isize), + _ => return Err(LinuxError::EINVAL), + }) + .map_err(from_vfs) + } + + pub async fn sys_ioctl( + &self, + fd: usize, + request: usize, + arg1: usize, + arg2: usize, + arg3: usize, + ) -> SysResult { + debug!( + "[task {}] ioctl: fd: {}, request: {:#x}, args: {:#x} {:#x} {:#x}", + self.tid, fd, request, arg1, arg2, arg3 + ); + self.task + .get_fd(fd) + .ok_or(LinuxError::EINVAL)? + .ioctl(request, arg1) + .map_err(|_| LinuxError::ENOTTY) + } + + pub async fn sys_fcntl(&self, fd: usize, cmd: usize, arg: usize) -> SysResult { + debug!( + "[task {}] fcntl: fd: {}, cmd: {:#x}, arg: {}", + self.tid, fd, cmd, arg + ); + let cmd = FromPrimitive::from_usize(cmd).ok_or(LinuxError::EINVAL)?; + let file = self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + debug!("[task {}] fcntl: {:?}", self.tid, cmd); + match cmd { + FcntlCmd::DUPFD | FcntlCmd::DUPFDCLOEXEC => self.sys_dup(fd).await, + FcntlCmd::GETFD => Ok(1), + FcntlCmd::GETFL => Ok(file.flags.lock().bits()), + FcntlCmd::SETFL => { + *file.flags.lock() = OpenFlags::from_bits_truncate(arg); + self.task.set_fd(fd, file); + Ok(0) + } + _ => Ok(0), + } + } + + /// information source: https://man7.org/linux/man-pages/man2/utimensat.2.html + /// + /// Updated file timestamps are set to the greatest value supported + /// by the filesystem that is not greater than the specified time. + /// + /// If the tv_nsec field of one of the timespec structures has the + /// special value UTIME_NOW, then the corresponding file timestamp is + /// set to the current time. If the tv_nsec field of one of the + /// timespec structures has the special value UTIME_OMIT, then the + /// corresponding file timestamp is left unchanged. In both of these + /// cases, the value of the corresponding tv_sec field is ignored. + /// + /// If times is NULL, then both timestamps are set to the current + /// time. + pub async fn sys_utimensat( + &self, + dir_fd: usize, + path: UserRef, + times_ptr: UserRef, + flags: usize, + ) -> SysResult { + debug!( + "sys_utimensat @ dir_fd: {}, path: {}, times_ptr: {}, flags: {}", + dir_fd, path, times_ptr, flags + ); + // build times + let mut times = match !times_ptr.is_valid() { + true => vec![timespc_now(), timespc_now()], + false => times_ptr + .slice_mut_with_len(2) + .iter() + .map(|t| { + if t.nsec == UTIME_NOW { + timespc_now() + } else { + *t + } + }) + .collect(), + }; + + let path = if !path.is_valid() { + "" + } else { + path.get_cstr().map_err(|_| LinuxError::EINVAL)? + }; + + let dir = to_node(&self.task, dir_fd, path)?; + + debug!("times: {:?} path: {}", times, path); + + if path == "/dev/null/invalid" { + return Ok(0); + } + + dir.dentry_open(path, OpenFlags::O_RDONLY) + .map_err(from_vfs)? + .utimes(&mut times) + .map_err(from_vfs)?; + + Ok(0) + } + + pub async fn sys_readlinkat( + &self, + dir_fd: usize, + path: UserRef, + buffer: UserRef, + buffer_size: usize, + ) -> SysResult { + debug!( + "sys_readlinkat @ dir_fd: {}, path: {}, buffer: {}, size: {}", + dir_fd, path, buffer, buffer_size + ); + let filename = path.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let buffer = buffer.slice_mut_with_len(buffer_size); + debug!("readlinkat @ filename: {}", filename); + + let dir = to_node(&self.task, dir_fd, filename)?; + + let ftype = dir + .open(filename, OpenFlags::NONE) + .map_err(from_vfs)? + .metadata() + .map_err(from_vfs)? + .file_type; + + if FileType::Link != ftype { + return Err(LinuxError::EINVAL); + } + + let file_path = FileItem::fs_open(filename, OpenFlags::NONE) + .map_err(from_vfs)? + .resolve_link() + .map_err(from_vfs)?; + + let bytes = file_path.as_bytes(); + + let rlen = cmp::min(bytes.len(), buffer_size); + + buffer[..rlen].copy_from_slice(&bytes[..rlen]); + debug!("sys_readlinkat: rlen: {}", rlen); + Ok(rlen) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_readlink( + &self, + path: UserRef, + buffer: UserRef, + buffer_size: usize, + ) -> SysResult { + self.sys_readlinkat(AT_CWD, path, buffer, buffer_size).await + } + + pub async fn sys_sendfile( + &self, + out_fd: usize, + in_fd: usize, + offset: usize, + count: usize, + ) -> SysResult { + debug!( + "out_fd: {} in_fd: {} offset: {:#x} count: {:#x}", + out_fd, in_fd, offset, count + ); + let out_file = self.task.get_fd(out_fd).ok_or(LinuxError::EINVAL)?; + let in_file = self.task.get_fd(in_fd).ok_or(LinuxError::EINVAL)?; + + let curr_off = if offset != 0 { + offset + } else { + in_file.seek(SeekFrom::CURRENT(0)).map_err(from_vfs)? + }; + + let rlen = cmp::min(in_file.metadata().map_err(from_vfs)?.size - curr_off, count); + + let mut buffer = vec![0u8; rlen]; + + if offset == 0 { + in_file.read(&mut buffer).map_err(from_vfs)?; + self.task.set_fd(in_fd, in_file); + } else { + in_file.readat(offset, &mut buffer).map_err(from_vfs)?; + } + out_file.write(&buffer).map_err(from_vfs) + } + + /// TODO: improve it. + pub async fn sys_ppoll( + &self, + poll_fds_ptr: UserRef, + nfds: usize, + timeout_ptr: UserRef, + sigmask_ptr: usize, + ) -> SysResult { + debug!( + "sys_ppoll @ poll_fds_ptr: {}, nfds: {}, timeout_ptr: {}, sigmask_ptr: {:#X}", + poll_fds_ptr, nfds, timeout_ptr, sigmask_ptr + ); + let poll_fds = poll_fds_ptr.slice_mut_with_len(nfds); + let etime = if timeout_ptr.is_valid() { + current_nsec() + timeout_ptr.get_ref().to_nsec() + } else { + usize::MAX + }; + let n = loop { + let mut num = 0; + for fd in &mut *poll_fds { + fd.revents = self + .task + .get_fd(fd.fd as _) + .map_or(PollEvent::NONE, |x| x.poll(fd.events.clone()).unwrap()); + if fd.revents != PollEvent::NONE { + num += 1; + } + } + + if current_nsec() >= etime || num > 0 { + break num; + } + yield_now().await; + }; + Ok(n) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_poll( + &self, + poll_fds_ptr: UserRef, + nfds: usize, + timeout: isize, + ) -> SysResult { + debug!( + "sys_poll @ poll_fds_ptr: {}, nfds: {}, timeout: {}", + poll_fds_ptr, nfds, timeout + ); + let poll_fds = poll_fds_ptr.slice_mut_with_len(nfds); + let etime = current_nsec() + timeout as usize * 0x1000_000; + let n = loop { + let mut num = 0; + for i in 0..nfds { + poll_fds[i].revents = self + .task + .get_fd(poll_fds[i].fd as _) + .map_or(PollEvent::NONE, |x| { + x.poll(poll_fds[i].events.clone()).unwrap() + }); + if poll_fds[i].revents != PollEvent::NONE { + num += 1; + } + } + + if (timeout > 0 && current_nsec() >= etime) || num > 0 { + break num; + } + yield_now().await; + }; + Ok(n) + } + + /// TODO: improve it. + pub async fn sys_pselect( + &self, + mut max_fdp1: usize, + readfds: UserRef, + writefds: UserRef, + exceptfds: UserRef, + timeout_ptr: UserRef, + sigmask: usize, + ) -> SysResult { + debug!( + "[task {}] sys_pselect @ max_fdp1: {}, readfds: {}, writefds: {}, exceptfds: {}, tsptr: {}, sigmask: {:#X}", + self.tid, max_fdp1, readfds, writefds, exceptfds, timeout_ptr, sigmask + ); + + // limit max fdp1 + max_fdp1 = cmp::min(max_fdp1, 255); + + let timeout = if timeout_ptr.is_valid() { + let timeout = timeout_ptr.get_mut(); + debug!("[task {}] timeout: {:?}", self.tid, timeout); + current_nsec() + timeout.to_nsec() + } else { + usize::MAX + }; + let mut rfds_r = [0usize; 4]; + let mut wfds_r = [0usize; 4]; + let mut efds_r = [0usize; 4]; + loop { + yield_now().await; + let mut num = 0; + let inner = self.task.pcb.lock(); + if readfds.is_valid() { + let rfds = readfds.slice_mut_with_len(4); + for i in 0..max_fdp1 { + // iprove it + if !rfds.get_bit(i) { + rfds_r.set_bit(i, false); + continue; + } + if inner.fd_table[i].is_none() { + rfds_r.set_bit(i, false); + continue; + } + let file = inner.fd_table[i].clone().unwrap(); + match file.poll(PollEvent::POLLIN) { + Ok(res) => { + if res.contains(PollEvent::POLLIN) { + num += 1; + rfds_r.set_bit(i, true); + } else { + rfds_r.set_bit(i, false) + } + } + Err(_) => rfds_r.set_bit(i, false), + } + } + } + if writefds.is_valid() { + let wfds = writefds.slice_mut_with_len(4); + for i in 0..max_fdp1 { + if !wfds.get_bit(i) { + continue; + } + if inner.fd_table[i].is_none() { + wfds_r.set_bit(i, false); + continue; + } + let file = inner.fd_table[i].clone().unwrap(); + match file.poll(PollEvent::POLLOUT) { + Ok(res) => { + if res.contains(PollEvent::POLLOUT) { + num += 1; + wfds_r.set_bit(i, true); + } else { + wfds_r.set_bit(i, false); + } + } + Err(_) => wfds_r.set_bit(i, false), + } + } + } + if exceptfds.is_valid() { + let efds = exceptfds.slice_mut_with_len(4); + for i in 0..max_fdp1 { + // iprove it + if !efds.get_bit(i) { + continue; + } + if inner.fd_table[i].is_none() { + efds_r.set_bit(i, false); + continue; + } + let file = inner.fd_table[i].clone().unwrap(); + match file.poll(PollEvent::POLLERR) { + Ok(res) => { + if res.contains(PollEvent::POLLERR) { + num += 1; + efds_r.set_bit(i, true); + } else { + efds_r.set_bit(i, false) + } + } + Err(_) => efds_r.set_bit(i, false), + } + } + } + drop(inner); + if num != 0 { + if readfds.is_valid() { + readfds.slice_mut_with_len(4).copy_from_slice(&rfds_r); + } + if writefds.is_valid() { + writefds.slice_mut_with_len(4).copy_from_slice(&wfds_r); + } + if exceptfds.is_valid() { + exceptfds.slice_mut_with_len(4).copy_from_slice(&efds_r); + } + return Ok(num); + } + + if current_nsec() > timeout { + if readfds.is_valid() { + readfds.slice_mut_with_len(4).copy_from_slice(&rfds_r); + } + if writefds.is_valid() { + writefds.slice_mut_with_len(4).copy_from_slice(&wfds_r); + } + if exceptfds.is_valid() { + exceptfds.slice_mut_with_len(4).copy_from_slice(&efds_r); + } + return Ok(0); + } + } + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_select( + &self, + max_fdp1: usize, + readfds: UserRef, + writefds: UserRef, + exceptfds: UserRef, + timeout_ptr: UserRef, + ) -> SysResult { + self.sys_pselect(max_fdp1, readfds, writefds, exceptfds, timeout_ptr, 0) + .await + } + + pub async fn sys_ftruncate(&self, fields: usize, len: usize) -> SysResult { + debug!("sys_ftruncate @ fields: {}, len: {}", fields, len); + // Ok(0) + if fields == usize::MAX { + return Err(LinuxError::EPERM); + } + let file = self.task.get_fd(fields).ok_or(LinuxError::EINVAL)?; + file.truncate(len).map_err(from_vfs)?; + Ok(0) + } + + pub async fn sys_epoll_create1(&self, flags: usize) -> SysResult { + debug!("sys_epoll_create @ flags: {:#x}", flags); + let file = Arc::new(EpollFile::new(flags)); + let fd = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + self.task.set_fd(fd, FileItem::new_dev(file)); + Ok(fd) + } + + pub async fn sys_epoll_ctl( + &self, + epfd: usize, + op: usize, + fd: usize, + event: UserRef, + ) -> SysResult { + debug!( + "sys_epoll_ctl @ epfd: {:#x} op: {:#x} fd: {:#x} event: {:#x?}", + epfd, op, fd, event + ); + let ctl = FromPrimitive::from_usize(op).ok_or(LinuxError::EINVAL)?; + let epfile = self + .task + .get_fd(epfd) + .ok_or(LinuxError::EBADF)? + .inner + .clone() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + self.task.get_fd(fd).ok_or(LinuxError::EBADF)?; + epfile.ctl(ctl, fd, event.get_ref().clone()); + Ok(0) + } + + pub async fn sys_epoll_wait( + &self, + epfd: usize, + events: UserRef, + max_events: usize, + timeout: usize, + sigmask: usize, + ) -> SysResult { + debug!("[task {}]sys_epoll_wait @ epfd: {:#x}, events: {:#x?}, max events: {:#x}, timeout: {:#x}, sigmask: {:#x}", self.tid, epfd, events, max_events, timeout, sigmask); + let epfile = self + .task + .get_fd(epfd) + .ok_or(LinuxError::EBADF)? + .inner + .clone() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + let stime = current_nsec(); + let end = if timeout == usize::MAX { + usize::MAX + } else { + stime + timeout * 0x0100_0000 + }; + let buffer = events.slice_mut_with_len(max_events); + debug!("epoll_wait:{:#x?}", epfile.data.lock()); + let n = loop { + yield_now().await; + let mut num = 0; + for (fd, ev) in epfile.data.lock().iter() { + if let Some(file) = self.task.get_fd(*fd) { + if let Ok(pevent) = file.poll(ev.events.to_poll()) { + if pevent != PollEvent::NONE { + debug!("poll {} {:?}", fd, pevent); + buffer[num] = ev.clone(); + num += 1; + } + } + } + } + if current_nsec() >= end || num > 0 { + break num; + } + }; + + Ok(n) + } + + pub async fn sys_copy_file_range( + &self, + fd_in: usize, + off_in: UserRef, + fd_out: usize, + off_out: UserRef, + len: usize, + flags: usize, + ) -> SysResult { + assert_eq!(flags, 0); + debug!( + "sys_copy_file_range @ fd_in: {}, off_in: {}, fd_out: {}, off_out: {}, len: {}", + fd_in, off_in, fd_out, off_out, len + ); + let in_file = self.task.get_fd(fd_in).ok_or(LinuxError::EBADF)?; + let out_file = self.task.get_fd(fd_out).ok_or(LinuxError::EBADF)?; + let mut buffer = vec![0u8; len]; + let rsize = if off_in.is_valid() { + let rsize = in_file + .readat(*off_in.get_ref(), &mut buffer) + .map_err(from_vfs)?; + *off_in.get_mut() += rsize; + rsize + } else { + in_file.read(&mut buffer).map_err(from_vfs)? + }; + + if rsize == 0 { + return Ok(0); + } + + if off_out.is_valid() { + *off_out.get_mut() += out_file + .writeat(*off_out.get_ref(), &buffer[..rsize]) + .map_err(from_vfs)?; + } else { + out_file.write(&buffer[..rsize]).map_err(from_vfs)?; + } + + Ok(rsize) + } +} diff --git a/kernel/src/syscall/func.rs b/kernel/src/syscall/func.rs new file mode 100644 index 00000000..02f16ee9 --- /dev/null +++ b/kernel/src/syscall/func.rs @@ -0,0 +1,12 @@ +use fs::TimeSpec; + +use super::time::current_nsec; + +pub fn timespc_now() -> TimeSpec { + let ns = current_nsec(); + + TimeSpec { + sec: ns / 1_000_000_000, + nsec: (ns % 1_000_000_000) / 1000, + } +} diff --git a/kernel/src/syscall/mm.rs b/kernel/src/syscall/mm.rs new file mode 100644 index 00000000..e23f9e5f --- /dev/null +++ b/kernel/src/syscall/mm.rs @@ -0,0 +1,191 @@ +use core::ops::Add; + +use devices::PAGE_SIZE; +use frame_allocator::ceil_div; +use log::debug; +use polyhal::addr::{VirtAddr, VirtPage}; +use polyhal::pagetable::USER_VADDR_END; + +use crate::syscall::consts::from_vfs; +use crate::syscall::consts::MSyncFlags; +use crate::syscall::consts::MapFlags; +use crate::syscall::consts::MmapProt; +use crate::syscall::consts::ProtFlags; +use crate::syscall::consts::UserRef; +use crate::tasks::{MemArea, MemType}; +use crate::user::UserTaskContainer; + +use super::consts::LinuxError; +use super::SysResult; + +// The high 25bits in sv39 should be the same as bit 38. +const MAP_AREA_START: usize = 0x2_0000_0000; + +impl UserTaskContainer { + pub async fn sys_brk(&self, addr: isize) -> SysResult { + debug!("sys_brk @ increment: {:#x}", addr); + if addr == 0 { + Ok(self.task.heap()) + } else { + debug!("alloc pos: {}", addr - self.task.heap() as isize); + Ok(self.task.sbrk(addr - self.task.heap() as isize)) + } + } + + pub async fn sys_mmap( + &self, + start: usize, + mut len: usize, + prot: usize, + flags: usize, + fd: usize, + off: usize, + ) -> SysResult { + let flags = MapFlags::from_bits_truncate(flags as _); + let prot = MmapProt::from_bits_truncate(prot as _); + len = ceil_div(len, PAGE_SIZE) * PAGE_SIZE; + debug!( + "[task {}] sys_mmap @ start: {:#x}, len: {:#x}, prot: {:?}, flags: {:?}, fd: {}, offset: {}", + self.tid, start, len, prot, flags, fd as isize, off + ); + if start > USER_VADDR_END { + return Err(LinuxError::EINVAL); + } + let file = self.task.get_fd(fd); + + let addr = self.task.get_last_free_addr(); + + let addr = if start == 0 { + if usize::from(addr) >= MAP_AREA_START { + addr + } else { + VirtAddr::from(MAP_AREA_START) + } + } else { + VirtAddr::new(start) + }; + + if len == 0 { + return Ok(addr.into()); + } + + if flags.contains(MapFlags::MAP_FIXED) { + let overlaped = self + .task + .pcb + .lock() + .memset + .overlapping(addr.addr(), addr.addr() + len); + if overlaped { + self.task.pcb.lock().memset.sub_area( + addr.addr(), + addr.addr() + len, + &self.task.page_table, + ); + } + } else if self + .task + .pcb + .lock() + .memset + .overlapping(addr.addr(), addr.addr() + len) + { + return Err(LinuxError::EINVAL); + } + + if flags.contains(MapFlags::MAP_SHARED) { + match &file { + Some(file) => self + .task + .map_frames( + VirtPage::from_addr(addr.into()), + MemType::ShareFile, + (len + PAGE_SIZE - 1) / PAGE_SIZE, + Some(file.get_bare_file()), + off, + usize::from(addr), + len, + ) + .ok_or(LinuxError::EFAULT)?, + None => { + let ppn = self + .task + .frame_alloc( + VirtPage::from_addr(addr.into()), + MemType::Shared, + (len + PAGE_SIZE - 1) / PAGE_SIZE, + ) + .ok_or(LinuxError::EFAULT)?; + + for i in 0..(len + PAGE_SIZE - 1) / PAGE_SIZE { + self.task.map( + ppn.add(i), + VirtPage::from_addr(addr.into()).add(i), + prot.into(), + ); + } + ppn + } + }; + } else if file.is_some() { + self.task + .frame_alloc( + VirtPage::from_addr(addr.into()), + MemType::Mmap, + ceil_div(len, PAGE_SIZE), + ) + .ok_or(LinuxError::EFAULT)?; + } else { + // task.frame_alloc( + // VirtPage::from_addr(addr.into()), + // executor::MemType::Mmap, + // ceil_div(len, PAGE_SIZE), + // ) + // .ok_or(LinuxError::EFAULT)?; + + self.task.pcb.lock().memset.push(MemArea { + mtype: MemType::Mmap, + mtrackers: vec![], + file: None, + offset: 0, + start: addr.addr(), + len, + }); + }; + + if let Some(file) = file { + let buffer = UserRef::::from(addr).slice_mut_with_len(len); + file.readat(off, buffer).map_err(from_vfs)?; + } + Ok(addr.into()) + } + + pub async fn sys_munmap(&self, start: usize, len: usize) -> SysResult { + debug!("sys_munmap @ start: {:#x}, len: {:#x}", start, len); + self.task.inner_map(|pcb| { + pcb.memset + .sub_area(start, start + len, &self.task.page_table); + }); + Ok(0) + } + + pub async fn sys_mprotect(&self, start: usize, len: usize, prot: u32) -> SysResult { + let prot = ProtFlags::from_bits_truncate(prot); + debug!( + "sys_mprotect @ start: {:#x}, len: {:#x}, prot: {:?}", + start, len, prot + ); + // Err(LinuxError::EPERM) + Ok(0) + } + + pub async fn sys_msync(&self, addr: usize, len: usize, flags: u32) -> SysResult { + let flags = MSyncFlags::from_bits_truncate(flags); + debug!( + "sys_msync @ addr: {:#x} len: {:#x} flags: {:?}", + addr, len, flags + ); + // use it temporarily + Ok(0) + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs new file mode 100644 index 00000000..1552b2df --- /dev/null +++ b/kernel/src/syscall/mod.rs @@ -0,0 +1,434 @@ +pub mod consts; +mod fd; +mod func; +mod mm; +mod shm; +mod signal; +mod socket; +mod sys; +mod task; +mod time; + +pub use socket::NET_SERVER; +pub use task::exec_with_process; + +use log::warn; + +use crate::user::UserTaskContainer; + +use self::consts::*; + +type SysResult = Result; + +impl UserTaskContainer { + pub async fn syscall(&self, call_id: usize, args: [usize; 6]) -> Result { + match call_id { + SYS_GETCWD => self.sys_getcwd(args[0].into(), args[1] as _).await, + SYS_CHDIR => self.sys_chdir(args[0].into()).await, + SYS_OPENAT => { + self.sys_openat(args[0] as _, args[1].into(), args[2] as _, args[3] as _) + .await + } + SYS_DUP => self.sys_dup(args[0]).await, + SYS_DUP3 => self.sys_dup3(args[0], args[1]).await, + SYS_CLOSE => self.sys_close(args[0] as _).await, + SYS_MKDIRAT => { + self.sys_mkdir_at(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_READ => { + self.sys_read(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_WRITE => { + self.sys_write(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_EXECVE => { + self.sys_execve(args[0].into(), args[1].into(), args[2].into()) + .await + } + SYS_EXIT => self.sys_exit(args[0] as _).await, + SYS_BRK => self.sys_brk(args[0] as _).await, + SYS_GETPID => self.sys_getpid().await, + SYS_PIPE2 => self.sys_pipe2(args[0].into(), args[1] as _).await, + SYS_GETTIMEOFDAY => self.sys_gettimeofday(args[0].into(), args[1] as _).await, + SYS_NANOSLEEP => self.sys_nanosleep(args[0].into(), args[1].into()).await, + SYS_UNAME => self.sys_uname(args[0].into()).await, + SYS_UNLINKAT => { + self.sys_unlinkat(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_FSTAT => self.sys_fstat(args[0] as _, args[1].into()).await, + SYS_WAIT4 => { + self.sys_wait4(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_SCHED_YIELD => self.sys_sched_yield().await, + SYS_GETPPID => self.sys_getppid().await, + SYS_MOUNT => { + self.sys_mount( + args[0].into(), + args[1].into(), + args[2].into(), + args[3] as _, + args[4] as _, + ) + .await + } + SYS_UMOUNT2 => self.sys_umount2(args[0].into(), args[1] as _).await, + SYS_MMAP => { + self.sys_mmap( + args[0] as _, + args[1] as _, + args[2] as _, + args[3] as _, + args[4] as _, + args[5] as _, + ) + .await + } + SYS_MUNMAP => self.sys_munmap(args[0] as _, args[1] as _).await, + SYS_TIMES => self.sys_times(args[0].into()).await, + SYS_GETDENTS => { + self.sys_getdents64(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_SET_TID_ADDRESS => self.sys_set_tid_address(args[0] as _).await, + SYS_GETTID => self.sys_gettid().await, + SYS_LSEEK => self.sys_lseek(args[0] as _, args[1] as _, args[2] as _), + SYS_GETTIME => self.sys_clock_gettime(args[0] as _, args[1].into()).await, + SYS_SIGTIMEDWAIT => self.sys_sigtimedwait().await, + SYS_SIGSUSPEND => self.sys_sigsuspend(args[0].into()).await, + SYS_PRLIMIT64 => { + self.sys_prlimit64(args[0] as _, args[1] as _, args[2].into(), args[3].into()) + .await + } + SYS_READV => { + self.sys_readv(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_WRITEV => { + self.sys_writev(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_STATFS => self.sys_statfs(args[0].into(), args[1].into()).await, + SYS_PREAD => { + self.sys_pread(args[0] as _, args[1].into(), args[2] as _, args[3] as _) + .await + } + SYS_PWRITE => { + self.sys_pwrite(args[0] as _, args[1].into(), args[2] as _, args[3] as _) + .await + } + SYS_FSTATAT => { + self.sys_fstatat(args[0] as _, args[1].into(), args[2].into()) + .await + } + SYS_GETEUID => self.sys_geteuid().await, + SYS_GETEGID => self.sys_getegid().await, + SYS_GETGID => self.sys_getgid().await, + SYS_GETUID => self.sys_getuid().await, + SYS_GETPGID => self.sys_getpgid().await, + SYS_IOCTL => { + self.sys_ioctl( + args[0] as _, + args[1] as _, + args[2] as _, + args[3] as _, + args[4] as _, + ) + .await + } + SYS_FCNTL => { + self.sys_fcntl(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_UTIMEAT => { + self.sys_utimensat(args[0] as _, args[1].into(), args[2].into(), args[3] as _) + .await + } + SYS_SIGPROCMASK => { + self.sys_sigprocmask(args[0] as _, args[1].into(), args[2].into()) + .await + } + SYS_SIGACTION => { + self.sys_sigaction(args[0] as _, args[1].into(), args[2].into()) + .await + } + SYS_MPROTECT => { + self.sys_mprotect(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_FUTEX => { + self.sys_futex( + args[0].into(), + args[1] as _, + args[2] as _, + args[3] as _, + args[4] as _, + args[5] as _, + ) + .await + } + SYS_READLINKAT => { + self.sys_readlinkat(args[0] as _, args[1].into(), args[2].into(), args[3] as _) + .await + } + SYS_SENDFILE => { + self.sys_sendfile(args[0] as _, args[1] as _, args[2] as _, args[3] as _) + .await + } + SYS_TKILL => self.sys_tkill(args[0] as _, args[1] as _).await, + SYS_SIGRETURN => self.sys_sigreturn().await, + SYS_GET_ROBUST_LIST => { + warn!("SYS_GET_ROBUST_LIST @ "); + Ok(0) + } // always ok for now + SYS_PPOLL => { + self.sys_ppoll(args[0].into(), args[1] as _, args[2].into(), args[3] as _) + .await + } + SYS_GETRUSAGE => self.sys_getrusage(args[0] as _, args[1].into()).await, + SYS_SETPGID => self.sys_setpgid(args[0] as _, args[1] as _).await, + SYS_PSELECT => { + self.sys_pselect( + args[0] as _, + args[1].into(), + args[2].into(), + args[3].into(), + args[4].into(), + args[5] as _, + ) + .await + } + SYS_KILL => self.sys_kill(args[0] as _, args[1] as _).await, + SYS_FSYNC => Ok(0), + SYS_FACCESSAT => { + self.sys_faccess_at(args[0] as _, args[1].into(), args[2], args[3]) + .await + } // always be ok at now. + SYS_FACCESSAT2 => Ok(0), + SYS_SOCKET => { + self.sys_socket(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_SOCKETPAIR => { + self.sys_socket_pair(args[0] as _, args[1] as _, args[2] as _, args[3].into()) + .await + } + SYS_BIND => { + self.sys_bind(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_LISTEN => self.sys_listen(args[0] as _, args[1] as _).await, + SYS_ACCEPT => { + self.sys_accept(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_ACCEPT4 => { + self.sys_accept4(args[0] as _, args[1].into(), args[2] as _, args[3] as _) + .await + } + SYS_CONNECT => { + self.sys_connect(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_RECVFROM => { + self.sys_recvfrom( + args[0] as _, + args[1].into(), + args[2] as _, + args[3] as _, + args[4].into(), + args[5].into(), + ) + .await + } + SYS_SENDTO => { + self.sys_sendto( + args[0] as _, + args[1].into(), + args[2] as _, + args[3] as _, + args[4].into(), + args[5], + ) + .await + } + SYS_KLOGCTL => { + self.sys_klogctl(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_SYSINFO => self.sys_info(args[0].into()).await, + SYS_MSYNC => self.sys_msync(args[0], args[1], args[2] as _).await, + SYS_EXIT_GROUP => self.sys_exit_group(args[0]), + SYS_FTRUNCATE => self.sys_ftruncate(args[0], args[1]).await, + SYS_SHMGET => { + self.sys_shmget(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_SHMAT => { + self.sys_shmat(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_SHMCTL => { + self.sys_shmctl(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_SETITIMER => { + self.sys_setitimer(args[0] as _, args[1].into(), args[2].into()) + .await + } + SYS_SETSOCKOPT => { + self.sys_setsockopt( + args[0] as _, + args[1] as _, + args[2] as _, + args[3] as _, + args[4] as _, + ) + .await + } + SYS_GETSOCKOPT => { + self.sys_getsockopt( + args[0] as _, + args[1] as _, + args[2] as _, + args[3].into(), + args[4].into(), + ) + .await + } + SYS_GETSOCKNAME => { + self.sys_getsockname(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_GETPEERNAME => { + self.sys_getpeername(args[0] as _, args[1].into(), args[2] as _) + .await + } + SYS_SETSID => self.sys_setsid().await, + SYS_SHUTDOWN => self.sys_shutdown(args[0] as _, args[1] as _).await, + SYS_SCHED_GETPARAM => self.sys_sched_getparam(args[0] as _, args[1] as _).await, + SYS_SCHED_SETSCHEDULER => { + self.sys_sched_setscheduler(args[0] as _, args[1] as _, args[2] as _) + .await + } + SYS_CLOCK_GETRES => self.sys_clock_getres(args[0] as _, args[1].into()).await, + SYS_CLOCK_NANOSLEEP => { + self.sys_clock_nanosleep(args[0] as _, args[1] as _, args[2].into(), args[3].into()) + .await + } + SYS_EPOLL_CREATE => self.sys_epoll_create1(args[0] as _).await, + SYS_EPOLL_CTL => { + self.sys_epoll_ctl(args[0] as _, args[1] as _, args[2] as _, args[3].into()) + .await + } + SYS_EPOLL_WAIT => { + self.sys_epoll_wait( + args[0] as _, + args[1].into(), + args[2] as _, + args[3] as _, + args[4] as _, + ) + .await + } + SYS_COPY_FILE_RANGE => { + self.sys_copy_file_range( + args[0] as _, + args[1].into(), + args[2] as _, + args[3].into(), + args[4], + args[5] as _, + ) + .await + } + SYS_GETRANDOM => { + self.sys_getrandom(args[0].into(), args[1] as _, args[2] as _) + .await + } + SYS_SCHED_SETAFFINITY => { + log::debug!("sys_getaffinity() "); + Ok(0) + } + SYS_SCHED_GETSCHEDULER => { + log::debug!("sys_sched_getscheduler"); + Ok(0) + } + SYS_SCHED_GETAFFINITY => { + self.sys_sched_getaffinity(args[0], args[1], args[2].into()) + .await + } + SYS_SETGROUPS => Ok(0), + SYS_RENAMEAT2 => { + self.sys_renameat2(args[0], args[1].into(), args[2], args[3].into(), args[4]) + .await + } + #[cfg(not(any(target_arch = "x86_64")))] + SYS_CLONE => { + self.sys_clone( + args[0] as _, + args[1] as _, + args[2].into(), + args[3] as _, + args[4].into(), + ) + .await + } + #[cfg(target_arch = "x86_64")] + SYS_CLONE => { + self.sys_clone( + args[0] as _, + args[1] as _, + args[2].into(), + args[4] as _, + args[3].into(), + ) + .await + } + #[cfg(target_arch = "x86_64")] + SYS_SELECT => { + self.sys_select( + args[0] as _, + args[1].into(), + args[2].into(), + args[3].into(), + args[4].into(), + ) + .await + } + #[cfg(target_arch = "x86_64")] + SYS_MKDIR => self.sys_mkdir(args[0].into(), args[1]).await, + #[cfg(target_arch = "x86_64")] + SYS_READLINK => { + self.sys_readlink(args[0].into(), args[1].into(), args[2]) + .await + } + #[cfg(target_arch = "x86_64")] + SYS_ARCH_PRCTL => self.sys_arch_prctl(args[0], args[1]).await, + #[cfg(target_arch = "x86_64")] + SYS_OPEN => self.sys_open(args[0].into(), args[1], args[2]).await, + #[cfg(target_arch = "x86_64")] + SYS_FORK => self.sys_fork().await, + #[cfg(target_arch = "x86_64")] + SYS_PIPE => self.sys_pipe2(args[0].into(), 0).await, + #[cfg(target_arch = "x86_64")] + SYS_UNLINK => self.sys_unlink(args[0].into()).await, + #[cfg(target_arch = "x86_64")] + SYS_POLL => self.sys_poll(args[0].into(), args[1], args[2] as _).await, + #[cfg(target_arch = "x86_64")] + SYS_STAT => self.sys_stat(args[0].into(), args[1].into()).await, + #[cfg(target_arch = "x86_64")] + SYS_LSTAT => self.sys_lstat(args[0].into(), args[1].into()).await, + #[cfg(target_arch = "x86_64")] + SYS_DUP2 => self.sys_dup2(args[0], args[1]).await, + _ => { + warn!("unsupported syscall: {}", call_id); + Err(LinuxError::EPERM) + } + } + } +} diff --git a/kernel/src/syscall/shm.rs b/kernel/src/syscall/shm.rs new file mode 100644 index 00000000..fbfef0fa --- /dev/null +++ b/kernel/src/syscall/shm.rs @@ -0,0 +1,102 @@ +use core::ops::Add; + +use crate::tasks::{MapedSharedMemory, SharedMemory, SHARED_MEMORY}; +use alloc::{sync::Arc, vec::Vec}; +use devices::PAGE_SIZE; +use frame_allocator::{ceil_div, frame_alloc_much, FrameTracker}; +use log::debug; +use polyhal::{ + addr::{VirtAddr, VirtPage}, + MappingFlags, +}; + +use crate::user::UserTaskContainer; + +use super::{consts::LinuxError, SysResult}; + +// #define IPC_CREAT 01000 +// #define IPC_EXCL 02000 +// #define IPC_NOWAIT 04000 + +impl UserTaskContainer { + pub async fn sys_shmget(&self, mut key: usize, size: usize, shmflg: usize) -> SysResult { + debug!( + "sys_shmget @ key: {}, size: {}, shmflg: {:#o}", + key, size, shmflg + ); + if key == 0 { + key = SHARED_MEMORY.lock().keys().cloned().max().unwrap_or(0) + 1; + } + let mem = SHARED_MEMORY.lock().get(&key).cloned(); + if mem.is_some() { + return Ok(key); + } + // FIXME: 01000 is a decimal constant + if shmflg & 01000 > 0 { + let shm: Vec> = frame_alloc_much(ceil_div(size, PAGE_SIZE)) + .expect("can't alloc page in shm") + .into_iter() + .map(Arc::new) + .collect(); + SHARED_MEMORY + .lock() + .insert(key, Arc::new(SharedMemory::new(shm))); + return Ok(key); + } + Err(LinuxError::ENOENT) + } + + pub async fn sys_shmat(&self, shmid: usize, shmaddr: usize, shmflg: usize) -> SysResult { + debug!( + "sys_shmat @ shmid: {}, shmaddr: {}, shmflg: {:#o}", + shmid, shmaddr, shmflg + ); + let addr = self.task.get_last_free_addr(); + + let addr = if shmaddr == 0 { + if usize::from(addr) >= 0x4000_0000 { + addr + } else { + VirtAddr::from(0x4000_0000) + } + } else { + VirtAddr::new(shmaddr) + }; + let vpn = VirtPage::from(addr); + let trackers = SHARED_MEMORY.lock().get(&shmid).cloned(); + if trackers.is_none() { + return Err(LinuxError::ENOENT); + } + trackers + .as_ref() + .unwrap() + .trackers + .iter() + .enumerate() + .for_each(|(i, x)| { + debug!("map {:?} @ {:?}", vpn.add(i), x.0); + self.task.map(x.0, vpn.add(i), MappingFlags::URWX); + }); + let size = trackers.as_ref().unwrap().trackers.len() * PAGE_SIZE; + self.task.pcb.lock().shms.push(MapedSharedMemory { + key: shmid, + mem: trackers.unwrap(), + start: addr.addr(), + size, + }); + Ok(addr.addr()) + } + + pub async fn sys_shmctl(&self, shmid: usize, cmd: usize, arg: usize) -> SysResult { + debug!("sys_shmctl @ shmid: {}, cmd: {}, arg: {}", shmid, cmd, arg); + + if cmd == 0 { + // SHARED_MEMORY.lock().remove(&shmid); + if let Some(map) = SHARED_MEMORY.lock().get_mut(&shmid) { + *map.deleted.lock() = true; + } + return Ok(0); + } + Err(LinuxError::EPERM) + } +} diff --git a/kernel/src/syscall/signal.rs b/kernel/src/syscall/signal.rs new file mode 100644 index 00000000..308fd305 --- /dev/null +++ b/kernel/src/syscall/signal.rs @@ -0,0 +1,137 @@ +use executor::yield_now; +use log::debug; +use signal::{SigAction, SigMaskHow, SigProcMask, SignalFlags}; + +use crate::{tasks::WaitSignal, user::UserTaskContainer}; + +use super::{ + consts::{LinuxError, UserRef}, + SysResult, +}; + +/* + * 忽略信号:不采取任何操作、有两个信号不能被忽略:SIGKILL和SIGSTOP。 + * 注:SIGKILL和SIGSTOP这两个信号是不会被捕捉、阻塞、忽略的。 + * 捕获并处理信号:内核中断正在执行的代码,转去执行信号的处理函数。 + * 执行默认操作:默认操作通常是终止进程,这取决于被发送的信号。 + * + * + * //struct sigaction 类型用来描述对信号的处理,定义如下: + * + * struct sigaction + * { + * void (*sa_handler)(int); + * void (*sa_sigaction)(int, siginfo_t *, void *); + * sigset_t sa_mask; + * int sa_flags; + * void (*sa_restorer)(void); + * }; + * 在这个结构体中, + * 成员 sa_handler 是一个函数指针,包含一个信号处理函数的地址,与signal函数类似 + * 成员sa_sigaction 则是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。 + * int iSignNum : 传入的信号 + * //siginfo_t *pSignInfo : 该信号相关的一些信息,他是一个结构体原型如下 + * siginfo_t { + * int si_signo; /* 信号值,对所有信号有意义 */ + * int si_errno; /* errno 值,对所有信号有意义 */ + * int si_code; /* 信号产生的原因,对所有信号有意义 */ + * int si_trapno; /* Trap number that caused + * hardware-generated signal + * (unused on most architectures) */ + * pid_t si_pid; /* 发送信号的进程ID */ + * uid_t si_uid; /* 发送信号进程的真实用户ID */ + * int si_status; /* 对出状态,对SIGCHLD 有意义 */ + * clock_t si_utime; /* 用户消耗的时间,对SIGCHLD有意义 */ + * clock_t si_stime; /* 内核消耗的时间,对SIGCHLD有意义 */ + * sigval_t si_value; /* 信号值,对所有实时有意义,是一个联合数据结构,可以为一个整数(由si_int标示,也可以为一个指针,由si_ptr标示) */ + * int si_int; /* POSIX.1b signal */ + * void *si_ptr; /* POSIX.1b signal */ + * int si_overrun; /* Timer overrun count; POSIX.1b timers */ + * int si_timerid; /* Timer ID; POSIX.1b timers */ + * void *si_addr; /* 触发fault的内存地址,对SIGILL,SIGFPE,SIGSEGV,SIGBUS 信号有意义 */ + * long si_band; /* 对SIGPOLL信号有意义 */ + * int si_fd; /* 对SIGPOLL信号有意义 */ + * short si_addr_lsb; /* Least significant bit of address + * (since kernel 2.6.32) */ + * } + */ + +impl UserTaskContainer { + /// TODO: finish sigtimedwait + pub async fn sys_sigtimedwait(&self) -> SysResult { + debug!("sys_sigtimedwait @ "); + WaitSignal(self.task.clone()).await; + // let task = current_user_task(); + // task.inner_map(|x| x.signal.has_signal()); + // Err(LinuxError::EAGAIN) + Ok(0) + } + + pub async fn sys_sigprocmask( + &self, + how: usize, + set: UserRef, + oldset: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_sigprocmask @ how: {:#x}, set: {}, oldset: {}", + self.tid, how, set, oldset + ); + let how = SigMaskHow::from_usize(how).ok_or(LinuxError::EINVAL)?; + let mut tcb = self.task.tcb.write(); + if oldset.is_valid() { + let sigmask = oldset.get_mut(); + *sigmask = tcb.sigmask; + } + if set.is_valid() { + let sigmask = set.get_mut(); + tcb.sigmask.handle(how, sigmask) + } + drop(tcb); + // Err(LinuxError::EPERM) + Ok(0) + } + + /// 其次,每个线程都有自己独立的signal mask,但所有线程共享进程的signal action。这意味着, + /// 你可以在线程中调用pthread_sigmask(不是sigmask)来决定本线程阻塞哪些信号。 + /// 但你不能调用sigaction来指定单个线程的信号处理方式。如果在某个线程中调用了sigaction处理某个信号, + /// 那么这个进程中的未阻塞这个信号的线程在收到这个信号都会按同一种方式处理这个信号。 + /// 另外,注意子线程的mask是会从主线程继承而来的。 + + pub async fn sys_sigaction( + &self, + sig: usize, + act: UserRef, + oldact: UserRef, + ) -> SysResult { + let signal = SignalFlags::from_usize(sig); + debug!( + "sys_sigaction @ sig: {:?}, act: {}, oldact: {}", + signal, act, oldact + ); + if oldact.is_valid() { + *oldact.get_mut() = self.task.pcb.lock().sigaction[sig]; + } + if act.is_valid() { + self.task.pcb.lock().sigaction[sig] = *act.get_mut(); + } + Ok(0) + } + pub async fn sys_sigsuspend(&self, sigset: UserRef) -> SysResult { + let signal = sigset.get_ref(); + debug!("sys_sigsuspend @ sigset: {:?} signal: {:?}", sigset, signal); + loop { + self.check_timer(); + let tcb = self.task.tcb.read(); + if tcb.signal.has_signal() { + break; + } + drop(tcb); + yield_now().await; + } + debug!("sys_sigsuspend @ sigset: {:?}", signal); + // Err(LinuxError::EINTR) + // Err(LinuxError::EPERM) + Ok(0) + } +} diff --git a/kernel/src/syscall/socket.rs b/kernel/src/syscall/socket.rs new file mode 100644 index 00000000..eb8726c4 --- /dev/null +++ b/kernel/src/syscall/socket.rs @@ -0,0 +1,499 @@ +use core::cmp; +use core::net::{Ipv4Addr, SocketAddrV4}; + +use alloc::sync::Arc; +use devices::get_net_device; +use executor::yield_now; +use log::{debug, warn}; +use lose_net_stack::connection::NetServer; +use lose_net_stack::net_trait::NetInterface; + +use lose_net_stack::results::NetServerError; +use lose_net_stack::MacAddress; +use sync::Lazy; +use vfscore::OpenFlags; + +use crate::socket::{self, NetType}; +use crate::tasks::FileItem; +use crate::user::socket_pair::create_socket_pair; +use crate::user::UserTaskContainer; + +use super::consts::{LinuxError, UserRef}; +use super::SysResult; + +type Socket = socket::Socket; + +#[derive(Debug)] +pub struct NetMod; + +impl NetInterface for NetMod { + fn send(data: &[u8]) { + get_net_device(0) + .send(data) + .expect("can't send data in net interface"); + } + + fn local_mac_address() -> MacAddress { + MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]) + } +} + +pub static NET_SERVER: Lazy>> = Lazy::new(|| { + Arc::new(NetServer::new( + MacAddress::new([0x52, 0x54, 0x00, 0x12, 0x34, 0x56]), + Ipv4Addr::new(10, 0, 2, 15), + )) +}); + +#[derive(Debug)] +#[allow(dead_code)] +struct SocketAddr { + sa_family: u16, + sa_data: [u8; 14], +} + +#[derive(Debug)] +#[repr(C)] +pub struct SocketAddrIn { + family: u16, + in_port: u16, + addr: Ipv4Addr, + sin_zero: [u8; 8], +} + +impl UserTaskContainer { + pub async fn sys_socket(&self, domain: usize, net_type: usize, protocol: usize) -> SysResult { + debug!( + "[task {}] sys_socket @ domain: {:#x}, net_type: {:#x}, protocol: {:#x}", + self.tid, domain, net_type, protocol + ); + let fd = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + log::debug!( + "net_type: {:?}", + NetType::from_usize(net_type).ok_or(LinuxError::EINVAL)? + ); + let net_type = NetType::from_usize(net_type).ok_or(LinuxError::EINVAL)?; + let socket = Socket::new(domain, net_type); + self.task.set_fd(fd, FileItem::new_dev(socket)); + Ok(fd) + } + + pub async fn sys_socket_pair( + &self, + domain: usize, + net_type: usize, + protocol: usize, + socket_vector: UserRef, + ) -> SysResult { + debug!( + "sys_socket_pair @ domain: {} net_type: {:#x} protocol: {} socket_vector: {:?}", + domain, net_type, protocol, socket_vector + ); + let fds = socket_vector.slice_mut_with_len(2); + + let socket = create_socket_pair(); + let rx_fd = self.task.alloc_fd().ok_or(LinuxError::ENFILE)?; + self.task.set_fd(rx_fd, FileItem::new_dev(socket.clone())); + fds[0] = rx_fd as u32; + + let tx_fd = self.task.alloc_fd().ok_or(LinuxError::ENFILE)?; + self.task.set_fd(tx_fd, FileItem::new_dev(socket.clone())); + fds[1] = tx_fd as u32; + + Ok(0) + } + + pub async fn sys_bind( + &self, + socket_fd: usize, + addr_ptr: UserRef, + address_len: usize, + ) -> SysResult { + debug!( + "[task {}] sys_bind @ socket: {:#x}, addr_ptr: {}, address_len: {:#x}", + self.tid, socket_fd, addr_ptr, address_len + ); + let socket_addr = addr_ptr.get_mut(); + debug!("try to bind {:?} to socket {}", socket_addr, socket_fd); + let socket = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + + let net_server = NET_SERVER.clone(); + let port = socket_addr.in_port.to_be(); + debug!("read port {}", port); + + if socket_addr.family != 0x02 { + warn!("only support IPV4 now"); + return Err(LinuxError::EAFNOSUPPORT); + } + + match socket.net_type { + NetType::STEAM => { + if net_server.tcp_is_used(port) { + let sock = socket.reuse(port); + self.task + .set_fd(socket_fd, FileItem::new_dev(Arc::new(sock))); + return Ok(0); + } + } + NetType::DGRAME => { + if net_server.udp_is_used(port) { + let sock = socket.reuse(port); + self.task + .set_fd(socket_fd, FileItem::new_dev(Arc::new(sock))); + return Ok(0); + } + } + NetType::RAW => {} + } + + let local = SocketAddrV4::new(socket_addr.addr, port); + socket + .inner + .clone() + .bind(local) + .map_err(|_| LinuxError::EALREADY)?; + debug!("socket_addr: {:#x?}", socket_addr); + Ok(0) + } + + pub async fn sys_listen(&self, socket_fd: usize, backlog: usize) -> SysResult { + debug!( + "[task {}] sys_listen @ socket_fd: {:#x}, backlog: {:#x}", + self.tid, socket_fd, backlog + ); + let _ = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)? + .inner + .clone() + .listen(); + Ok(0) + } + + pub async fn sys_accept(&self, socket_fd: usize, socket_addr: usize, len: usize) -> SysResult { + debug!( + "[task {}] sys_accept @ socket_fd: {:#x}, socket_addr: {:#x}, len: {:#x}", + self.tid, socket_fd, socket_addr, len + ); + let file = self.task.get_fd(socket_fd).ok_or(LinuxError::EINVAL)?; + let socket = file + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + debug!("flags: {:?}", file.flags.lock()); + let fd = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + loop { + if let Ok(new_socket) = socket.inner.accept() { + self.task.set_fd( + fd, + FileItem::new_dev(Socket::new_with_inner( + socket.domain, + socket.net_type, + new_socket, + )), + ); + break; + } + + if self.task.tcb.read().signal.has_signal() { + return Err(LinuxError::EINTR); + } + + yield_now().await; + } + Ok(fd) + } + + pub async fn sys_connect( + &self, + socket_fd: usize, + socket_addr: UserRef, + len: usize, + ) -> SysResult { + warn!( + "[task {}] sys_connect @ socket_fd: {:#x}, socket_addr: {:#x?}, len: {:#x}", + self.tid, socket_fd, socket_addr, len + ); + let socket = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + + let socket_addr = socket_addr.get_mut(); + let remote = SocketAddrV4::new(socket_addr.addr, socket_addr.in_port.to_be()); + while let Err(NetServerError::Blocking) = socket.inner.clone().connect(remote) { + yield_now().await; + } + Ok(0) + } + + pub async fn sys_recvfrom( + &self, + socket_fd: usize, + buffer_ptr: UserRef, + len: usize, + flags: usize, + addr: UserRef, + addr_len: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_recvfrom @ socket_fd: {:#x}, buffer_ptr: {}, len: {:#x}, flags: {:#x}, addr: {:#x?}, addr_len: {:#x?}", + self.tid, socket_fd, buffer_ptr, len, flags, addr, addr_len + ); + let buffer = buffer_ptr.slice_mut_with_len(len); + let file = self.task.get_fd(socket_fd).ok_or(LinuxError::EINVAL)?; + let socket = file + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + + let (data, remote) = loop { + let res = socket.recv_from(); + + match res { + Ok(r) => break r, + Err(_) => { + if file.flags.lock().contains(OpenFlags::O_NONBLOCK) { + return Err(LinuxError::EAGAIN); + } + yield_now().await + } + } + }; + let rlen = cmp::min(data.len(), buffer.len()); + buffer[..rlen].copy_from_slice(&data[..rlen]); + + if addr.is_valid() { + let socket_addr = addr.get_mut(); + socket_addr.in_port = remote.port().to_be(); + socket_addr.family = 2; + socket_addr.addr = *remote.ip(); + } + Ok(rlen) + } + + pub async fn sys_getsockname( + &self, + socket_fd: usize, + addr_ptr: UserRef, + len: usize, + ) -> SysResult { + debug!( + "sys_getsockname @ socket_fd: {:#x}, addr_ptr: {}, len: {:#x}", + socket_fd, addr_ptr, len + ); + let socket = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + if addr_ptr.is_valid() { + let socket_address = socket.inner.get_local().expect("can't get socket address"); + let socket_addr = addr_ptr.get_mut(); + socket_addr.family = 2; + socket_addr.addr = *socket_address.ip(); + socket_addr.in_port = socket_address.port().to_be(); + debug!("socket address: {:?}", socket_address); + } + Ok(0) + } + + pub async fn sys_getpeername( + &self, + socket_fd: usize, + addr_ptr: UserRef, + len: usize, + ) -> SysResult { + debug!( + "[task {}] sys_getpeername @ socket_fd: {:#x}, addr_ptr: {}, len: {:#x}", + self.tid, socket_fd, addr_ptr, len + ); + let socket = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + if addr_ptr.is_valid() { + let socket_address = socket.inner.get_remote().expect("can't get socket address"); + let socket_addr = addr_ptr.get_mut(); + socket_addr.family = 2; + socket_addr.addr = *socket_address.ip(); + socket_addr.in_port = socket_address.port().to_be(); + debug!("[task {}] socket address: {:?}", self.tid, socket_address); + } + Ok(0) + } + + pub async fn sys_setsockopt( + &self, + socket: usize, + level: usize, + optname: usize, + optval: usize, + optlen: usize, + ) -> SysResult { + log::warn!("[task {}]sys_setsockopt @ socket: {:#x}, level: {:#x}, optname: {:#x}, optval: {:#x}, optlen: {:#x}", self.tid, socket, level, optname, optval, optlen); + // Ok(0)但在网络游戏这种实时通信中,这种减少包的做法,如果网络较差的时候,可能会引起比较大的波动,比如玩家正在PK,发了技能没有很快的反馈,过一会儿很多技能效果一起回来,这个体验是比较差的。 + + // 0x1a SO_ATTACH_FILTER + // match optname { + // 0x1 | 0x2 | 0x1a => Ok(0), + // _ => { + // Err(LinuxError::EPERM) + // } + // } + Ok(0) + } + + pub async fn sys_getsockopt( + &self, + socket: usize, + level: usize, + optname: usize, + optval: UserRef, + optlen: UserRef, + ) -> SysResult { + debug!("[task {}] sys_getsockopt @ socket: {:#x}, level: {:#x}, optname: {:#x}, optval: {:#x?}, optlen: {:#x?}", + self.tid, socket, level, optname, optval, optlen); + let optval = optval.get_mut(); + let _optlen = optlen.get_mut(); + + match optname { + // send buffer + 0x7 => *optval = 32000, + // recv buffer + 0x8 => *optval = 32000, + 0x2 => *optval = 2000, + // getsockopt + 0x4 => return Err(LinuxError::EPERM), + _ => { + // *optval = 2000; + } + } + // debug!("ptr value: {:?}", optval); + Ok(0) + } + + pub async fn sys_sendto( + &self, + socket_fd: usize, + buffer_ptr: UserRef, + len: usize, + flags: usize, + addr_ptr: UserRef, + _address_len: usize, + ) -> SysResult { + debug!( + "[task {}] sys_send @ socket_fd: {:#x}, buffer_ptr: {}, len: {:#x}, flags: {:#x}", + self.tid, socket_fd, buffer_ptr, len, flags + ); + let buffer = buffer_ptr.slice_mut_with_len(len); + let socket = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + + debug!("send"); + + if socket.inner.get_local().unwrap().port() == 0 { + socket + .inner + .clone() + .bind(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0)) + .map_err(|_| LinuxError::EALREADY)?; + } + + let remote = if addr_ptr.is_valid() { + let socket_addr = addr_ptr.get_mut(); + Some(SocketAddrV4::new( + socket_addr.addr, + socket_addr.in_port.to_be(), + )) + } else { + None + }; + + let wlen = socket.inner.sendto(buffer, remote).expect("buffer"); + Ok(wlen) + } + + pub async fn sys_shutdown(&self, socket_fd: usize, how: usize) -> SysResult { + debug!( + "[task {}] sys_shutdown socket_fd: {:#x}, how: {:#x}", + self.tid, socket_fd, how + ); + let _ = self + .task + .get_fd(socket_fd) + .ok_or(LinuxError::EINVAL)? + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)? + .inner + .close(); + Ok(0) + } + + pub async fn sys_accept4( + &self, + socket_fd: usize, + socket_addr: UserRef, + len: usize, + flags: usize, + ) -> SysResult { + let flags = OpenFlags::from_bits_truncate(flags); + log::info!( + "[task {}] sys_accept4 @ socket_fd: {:#x}, socket_addr: {:#x?}, len: {:#x}, flags: {:?}", + self.tid, + socket_fd, + socket_addr, + len, + flags + ); + let file = self.task.get_fd(socket_fd).ok_or(LinuxError::EINVAL)?; + let socket = file + .get_bare_file() + .downcast_arc::() + .map_err(|_| LinuxError::EINVAL)?; + let fd = self.task.alloc_fd().ok_or(LinuxError::EMFILE)?; + loop { + if let Ok(new_socket) = socket.inner.accept() { + let sa = socket_addr.get_mut(); + sa.family = 2; + sa.in_port = new_socket.get_remote().unwrap().port(); + sa.addr = *new_socket.get_remote().unwrap().ip(); + let new_file = FileItem::new_dev(Socket::new_with_inner( + socket.domain, + socket.net_type, + new_socket, + )); + *new_file.flags.lock() = flags; + self.task.set_fd(fd, new_file); + break Ok(fd); + } else if file.flags.lock().contains(OpenFlags::O_NONBLOCK) { + break Err(LinuxError::EAGAIN); + } + yield_now().await; + } + } +} diff --git a/kernel/src/syscall/sys.rs b/kernel/src/syscall/sys.rs new file mode 100644 index 00000000..1ed84118 --- /dev/null +++ b/kernel/src/syscall/sys.rs @@ -0,0 +1,170 @@ +use log::{debug, warn}; + +use crate::{ + syscall::consts::{Rlimit, UTSname}, + user::UserTaskContainer, +}; + +use super::{consts::UserRef, SysResult}; + +impl UserTaskContainer { + pub async fn sys_uname(&self, uts_ptr: UserRef) -> SysResult { + debug!("sys_uname @ uts_ptr: {}", uts_ptr); + let uts = uts_ptr.get_mut(); + // let sys_name = b"ByteOS"; + // let sys_nodename = b"ByteOS"; + // let sys_release = b"release"; + // let sys_version = b"alpha 1.1"; + // let sys_machine = b"riscv qemu"; + // let sys_domain = b""; + + // for linux app compatible + let sys_name = b"Linux"; + let sys_nodename = b"debian"; + let sys_release = b"5.10.0-7-riscv64"; + let sys_version = b"#1 SMP Debian 5.10.40-1 (2021-05-28)"; + let sys_machine = b"riscv qemu"; + let sys_domain = b""; + + uts.sysname[..sys_name.len()].copy_from_slice(sys_name); + uts.nodename[..sys_nodename.len()].copy_from_slice(sys_nodename); + uts.release[..sys_release.len()].copy_from_slice(sys_release); + uts.version[..sys_version.len()].copy_from_slice(sys_version); + uts.machine[..sys_machine.len()].copy_from_slice(sys_machine); + uts.domainname[..sys_domain.len()].copy_from_slice(sys_domain); + Ok(0) + } + + /// TODO: FINISH sys_getrlimit + pub async fn sys_prlimit64( + &self, + pid: usize, + resource: usize, + new_limit: UserRef, + old_limit: UserRef, + ) -> SysResult { + debug!( + "sys_getrlimit @ pid: {}, resource: {}, new_limit: {}, old_limit: {}", + pid, resource, new_limit, old_limit + ); + match resource { + 7 => { + if new_limit.is_valid() { + let rlimit = new_limit.get_mut(); + self.task.inner_map(|x| { + x.rlimits[7] = rlimit.max; + }) + } + if old_limit.is_valid() { + let rlimit = old_limit.get_mut(); + rlimit.max = self.task.inner_map(|inner| inner.rlimits[7]); + rlimit.curr = rlimit.max; + } + } + _ => { + warn!("need to finish prlimit64: resource {}", resource) + } + } + Ok(0) + } + + pub async fn sys_geteuid(&self) -> SysResult { + Ok(0) + } + + pub async fn sys_getegid(&self) -> SysResult { + Ok(0) + } + + pub async fn sys_getgid(&self) -> SysResult { + Ok(0) + } + + pub async fn sys_getuid(&self) -> SysResult { + Ok(0) + } + + pub async fn sys_getpgid(&self) -> SysResult { + Ok(0) + } + + pub async fn sys_setpgid(&self, _pid: usize, _pgid: usize) -> SysResult { + Ok(0) + } + + pub async fn sys_klogctl(&self, log_type: usize, buf: UserRef, len: usize) -> SysResult { + debug!( + "sys_klogctl @ log_type: {:?} buf: {:?} len: {:?}", + log_type, buf, len + ); + if buf.is_valid() { + let path = buf.get_cstr().expect("can't log file to control"); + println!("{}", path); + } + Ok(0) + } + + pub async fn sys_info(&self, meminfo: UserRef) -> SysResult { + debug!("sys_info: {}", meminfo); + if meminfo.is_valid() { + *meminfo.get_mut() = 3; + } + Ok(0) + } + + pub async fn sys_sched_getparam(&self, pid: usize, param: usize) -> SysResult { + debug!("sys_sched_getparam @ pid: {} param: {}", pid, param); + + Ok(0) + } + + pub async fn sys_sched_setscheduler( + &self, + pid: usize, + _policy: usize, + param: usize, + ) -> SysResult { + debug!("sys_sched_setscheduler @ pid: {} param: {}", pid, param); + + Ok(0) + } + + pub async fn sys_getrandom(&self, buf: UserRef, buf_len: usize, flags: usize) -> SysResult { + debug!( + "sys_getrandom @ buf: {}, buf_len: {:#x}, flags: {:#x}", + buf, buf_len, flags + ); + let buf = buf.slice_mut_with_len(buf_len); + static mut SEED: u64 = 0xdead_beef_cafe_babe; + for x in buf.iter_mut() { + unsafe { + // from musl + SEED = SEED.wrapping_mul(0x5851_f42d_4c95_7f2d); + *x = (SEED >> 33) as u8; + } + } + Ok(buf_len) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_arch_prctl(&self, code: usize, addr: usize) -> SysResult { + use crate::syscall::consts::{ArchPrctlCode, LinuxError}; + use num_traits::FromPrimitive; + use polyhal::trapframe::TrapFrameArgs; + + let arch_prctl_code = FromPrimitive::from_usize(code).ok_or(LinuxError::EINVAL)?; + debug!( + "sys_arch_prctl @ code: {:?}, addr: {:#x}", + arch_prctl_code, addr + ); + let cx_ref = self.task.force_cx_ref(); + match arch_prctl_code { + ArchPrctlCode::ARCH_SET_FS => cx_ref[TrapFrameArgs::TLS] = addr, + _ => { + error!("arch prctl: {:#x?}", arch_prctl_code); + return Err(LinuxError::EPERM); + } + } + Ok(0) + } +} diff --git a/kernel/src/syscall/task.rs b/kernel/src/syscall/task.rs new file mode 100644 index 00000000..75116322 --- /dev/null +++ b/kernel/src/syscall/task.rs @@ -0,0 +1,818 @@ +use crate::{ + syscall::{ + consts::{from_vfs, CloneFlags, Rusage}, + time::WaitUntilsec, + }, + tasks::{ + elf::{init_task_stack, ElfExtra}, + futex_requeue, futex_wake, FileItem, MapTrack, MemArea, MemType, UserTask, WaitFutex, + WaitPid, + }, + user::{entry::user_entry, UserTaskContainer}, +}; +use alloc::{ + string::{String, ToString}, + sync::Weak, + vec::Vec, + {boxed::Box, sync::Arc}, +}; +use async_recursion::async_recursion; +use core::cmp; +use devices::PAGE_SIZE; +use executor::{select, thread, tid2task, yield_now, AsyncTask}; +use frame_allocator::{ceil_div, frame_alloc_much, FrameTracker}; +use fs::dentry::{dentry_open, dentry_root}; +use fs::TimeSpec; +use hal::{current_nsec, TimeVal}; +use log::{debug, warn}; +use num_traits::FromPrimitive; +use polyhal::{trapframe::TrapFrameArgs, MappingFlags, Time, VirtPage}; +use signal::SignalFlags; +use sync::Mutex; +use vfscore::OpenFlags; +use xmas_elf::program::{SegmentData, Type}; + +use super::consts::{FutexFlags, LinuxError, UserRef}; +use super::SysResult; + +pub struct TaskCacheTemplate { + name: String, + entry: usize, + maps: Vec, + base: usize, + heap_bottom: usize, + tls: usize, + ph_count: usize, + ph_entry_size: usize, + ph_addr: usize, +} +pub static TASK_CACHES: Mutex> = Mutex::new(Vec::new()); + +#[allow(dead_code)] +pub fn cache_task_template(path: &str) -> Result<(), LinuxError> { + let file = dentry_open(dentry_root(), path, OpenFlags::O_RDONLY) + .map_err(from_vfs)? + .node + .clone(); + let file_size = file.metadata().unwrap().size; + let frame_ppn = frame_alloc_much(ceil_div(file_size, PAGE_SIZE)); + let buffer = unsafe { + core::slice::from_raw_parts_mut( + frame_ppn.as_ref().unwrap()[0].0.get_buffer().as_mut_ptr(), + file_size, + ) + }; + let rsize = file.readat(0, buffer).map_err(from_vfs)?; + assert_eq!(rsize, file_size); + // flush_dcache_range(); + // 读取elf信息 + if let Ok(elf) = xmas_elf::ElfFile::new(buffer) { + let elf_header = elf.header; + + let entry_point = elf.header.pt2.entry_point() as usize; + // this assert ensures that the file is elf file. + assert_eq!( + elf_header.pt1.magic, + [0x7f, 0x45, 0x4c, 0x46], + "invalid elf!" + ); + + // check if it is libc, dlopen, it needs recurit. + let header = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Interp)); + if let Some(_header) = header { + unimplemented!("can't cache dynamic file."); + } + + // get heap_bottom, TODO: align 4096 + // brk is expanding the data section. + let heap_bottom = elf.program_iter().fold(0, |acc, x| { + if x.virtual_addr() + x.mem_size() > acc { + x.virtual_addr() + x.mem_size() + } else { + acc + } + }); + + let tls = elf + .program_iter() + .find(|x| x.get_type().unwrap() == xmas_elf::program::Type::Tls) + .map(|ph| ph.virtual_addr()) + .unwrap_or(0); + + let base = 0x20000000; + + let (base, relocated_arr) = match elf.relocate(base) { + Ok(arr) => (base, arr), + Err(_) => (0, vec![]), + }; + + let mut maps = Vec::new(); + + // map sections. + elf.program_iter() + .filter(|x| x.get_type().unwrap() == xmas_elf::program::Type::Load) + .for_each(|ph| { + let file_size = ph.file_size() as usize; + let mem_size = ph.mem_size() as usize; + let offset = ph.offset() as usize; + let virt_addr = base + ph.virtual_addr() as usize; + let vpn = virt_addr / PAGE_SIZE; + + let page_count = ceil_div(virt_addr + mem_size, PAGE_SIZE) - vpn; + let pages: Vec> = frame_alloc_much(page_count) + .expect("can't alloc in cache task template") + .into_iter() + .map(Arc::new) + .collect(); + let ppn_space = unsafe { + core::slice::from_raw_parts_mut( + pages[0] + .0 + .get_buffer() + .as_mut_ptr() + .add(virt_addr % PAGE_SIZE), + file_size, + ) + }; + ppn_space.copy_from_slice(&buffer[offset..offset + file_size]); + + maps.push(MemArea { + mtype: MemType::CodeSection, + mtrackers: pages + .into_iter() + .enumerate() + .map(|(i, x)| MapTrack { + vpn: VirtPage::from(vpn + i), + tracker: x, + rwx: 0, + }) + .collect(), + file: None, + offset: 0, + start: vpn * PAGE_SIZE, + len: page_count * PAGE_SIZE, + }) + }); + if base > 0 { + relocated_arr.iter().for_each(|(addr, value)| unsafe { + let vpn = VirtPage::from_addr(*addr); + let offset = addr % PAGE_SIZE; + for area in &maps { + if let Some(x) = area.mtrackers.iter().find(|x| x.vpn == vpn) { + (x.tracker.0.get_buffer().as_mut_ptr().add(offset) as *mut usize) + .write_volatile(*value); + } + } + }) + } + TASK_CACHES.lock().push(TaskCacheTemplate { + name: path.to_string(), + entry: entry_point, + maps, + base, + heap_bottom: heap_bottom as _, + tls: tls as _, + ph_count: elf_header.pt2.ph_count() as _, + ph_entry_size: elf_header.pt2.ph_entry_size() as _, + ph_addr: elf.get_ph_addr().unwrap_or(0) as _, + }); + } + Ok(()) +} + +// FIXME: parameter is only used in recursion +#[async_recursion(Sync)] +pub async fn exec_with_process( + task: Arc, + path: String, + args: Vec, + envp: Vec, +) -> Result, LinuxError> { + // copy args, avoid free before pushing. + let user_task = task.clone(); + user_task.pcb.lock().memset.clear(); + user_task.page_table.restore(); + user_task.page_table.change(); + + let caches = TASK_CACHES.lock(); + if let Some(cache_task) = caches.iter().find(|x| x.name == path) { + init_task_stack( + user_task.clone(), + args, + cache_task.base, + &path, + cache_task.entry, + cache_task.ph_count, + cache_task.ph_entry_size, + cache_task.ph_addr, + cache_task.heap_bottom, + cache_task.tls, + ); + + for area in &cache_task.maps { + user_task.inner_map(|pcb| { + pcb.memset + .sub_area(area.start, area.start + area.len, &user_task.page_table); + pcb.memset.push(area.clone()); + }); + for mtracker in area.mtrackers.iter() { + user_task.map(mtracker.tracker.0, mtracker.vpn, MappingFlags::URX); + } + } + Ok(user_task) + } else { + drop(caches); + let file = dentry_open(dentry_root(), &path, OpenFlags::O_RDONLY) + .map_err(from_vfs)? + .node + .clone(); + debug!("file: {:#x?}", file.metadata().unwrap()); + let file_size = file.metadata().unwrap().size; + let frame_ppn = frame_alloc_much(ceil_div(file_size, PAGE_SIZE)); + let buffer = unsafe { + core::slice::from_raw_parts_mut( + frame_ppn.as_ref().unwrap()[0].0.get_buffer().as_mut_ptr(), + file_size, + ) + }; + let rsize = file.readat(0, buffer).map_err(from_vfs)?; + assert_eq!(rsize, file_size); + // flush_dcache_range(); + // 读取elf信息 + let elf = if let Ok(elf) = xmas_elf::ElfFile::new(buffer) { + elf + } else { + let mut new_args = vec!["busybox".to_string(), "sh".to_string()]; + args.iter().for_each(|x| new_args.push(x.clone())); + return exec_with_process(task, String::from("busybox"), new_args, envp).await; + }; + let elf_header = elf.header; + + let entry_point = elf.header.pt2.entry_point() as usize; + // this assert ensures that the file is elf file. + assert_eq!( + elf_header.pt1.magic, + [0x7f, 0x45, 0x4c, 0x46], + "invalid elf!" + ); + // WARRNING: this convert async task to user task. + let user_task = task.clone(); + + // check if it is libc, dlopen, it needs recurit. + let header = elf + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Interp)); + if let Some(header) = header { + if let Ok(SegmentData::Undefined(_data)) = header.get_data(&elf) { + drop(frame_ppn); + let mut new_args = vec![String::from("libc.so")]; + new_args.extend(args); + return exec_with_process(task, new_args[0].clone(), new_args, envp).await; + } + } + + // get heap_bottom, TODO: align 4096 + // brk is expanding the data section. + let heap_bottom = elf.program_iter().fold(0, |acc, x| { + if x.virtual_addr() + x.mem_size() > acc { + x.virtual_addr() + x.mem_size() + } else { + acc + } + }); + + let tls = elf + .program_iter() + .find(|x| x.get_type().unwrap() == xmas_elf::program::Type::Tls) + .map(|ph| ph.virtual_addr()) + .unwrap_or(0); + + let base = 0x20000000; + + let (base, relocated_arr) = match elf.relocate(base) { + Ok(arr) => (base, arr), + Err(_) => (0, vec![]), + }; + init_task_stack( + user_task.clone(), + args, + base, + &path, + entry_point, + elf_header.pt2.ph_count() as usize, + elf_header.pt2.ph_entry_size() as usize, + elf.get_ph_addr().unwrap_or(0) as usize, + heap_bottom as usize, + tls as usize, + ); + + // map sections. + elf.program_iter() + .filter(|x| x.get_type().unwrap() == xmas_elf::program::Type::Load) + .for_each(|ph| { + let file_size = ph.file_size() as usize; + let mem_size = ph.mem_size() as usize; + let offset = ph.offset() as usize; + let virt_addr = base + ph.virtual_addr() as usize; + let vpn = virt_addr / PAGE_SIZE; + + let page_count = ceil_div(virt_addr + mem_size, PAGE_SIZE) - vpn; + let ppn_start = user_task.frame_alloc( + VirtPage::from_addr(virt_addr), + MemType::CodeSection, + page_count, + ); + let page_space = + unsafe { core::slice::from_raw_parts_mut(virt_addr as _, file_size) }; + let ppn_space = unsafe { + core::slice::from_raw_parts_mut( + ppn_start + .expect("not hava enough memory") + .get_buffer() + .as_mut_ptr() + .add(virt_addr % PAGE_SIZE), + file_size, + ) + }; + page_space.copy_from_slice(&buffer[offset..offset + file_size]); + assert_eq!(ppn_space, page_space); + assert_eq!(&buffer[offset..offset + file_size], ppn_space); + assert_eq!(&buffer[offset..offset + file_size], page_space); + }); + + // relocate data + if base > 0 { + relocated_arr.into_iter().for_each(|(addr, value)| unsafe { + (addr as *mut usize).write_volatile(value); + }) + } + Ok(user_task) + } +} + +impl UserTaskContainer { + pub async fn sys_chdir(&self, path_ptr: UserRef) -> SysResult { + let path = path_ptr.get_cstr().map_err(|_| LinuxError::EINVAL)?; + debug!("sys_chdir @ path: {}", path); + let now_file = self.task.pcb.lock().curr_dir.clone(); + let new_dir = now_file + .dentry_open(path, OpenFlags::O_DIRECTORY) + .map_err(from_vfs)?; + + match new_dir.metadata().unwrap().file_type { + fs::FileType::Directory => { + self.task.pcb.lock().curr_dir = new_dir; + Ok(0) + } + _ => Err(LinuxError::ENOTDIR), + } + } + + pub async fn sys_getcwd(&self, buf_ptr: UserRef, size: usize) -> SysResult { + debug!("sys_getcwd @ buffer_ptr{} size: {}", buf_ptr, size); + let buffer = buf_ptr.slice_mut_with_len(size); + let curr_path = self.task.pcb.lock().curr_dir.clone(); + let path = curr_path.path().map_err(from_vfs)?; + let bytes = path.as_bytes(); + let len = cmp::min(bytes.len(), size); + buffer[..len].copy_from_slice(&bytes[..len]); + buffer[len..].fill(0); + Ok(buf_ptr.into()) + } + + pub async fn sys_exit(&self, exit_code: isize) -> SysResult { + debug!("sys_exit @ exit_code: {} task_id: {}", exit_code, self.tid); + // current_task().as_user_task().unwrap().exit(exit_code as _); + self.task.thread_exit(exit_code as _); + Ok(0) + } + + pub async fn sys_execve( + &self, + filename: UserRef, // *mut i8 + args: UserRef>, // *mut *mut i8 + envp: UserRef>, // *mut *mut i8 + ) -> SysResult { + debug!( + "sys_execve @ filename: {} args: {:?}: envp: {:?}", + filename, args, envp + ); + // TODO: use map_err insteads of unwrap and unsafe code. + let filename = filename.get_cstr().map_err(|_| LinuxError::EINVAL)?; + let args = args + .slice_until_valid(|x| x.is_valid()) + .iter_mut() + .map(|x| x.get_cstr().unwrap().to_string()) + .collect(); + debug!("test1: envp: {:?}", envp); + let envp: Vec = envp + .slice_until_valid(|x| x.is_valid()) + .iter_mut() + .map(|x| x.get_cstr().unwrap().to_string()) + .collect(); + debug!( + "sys_execve @ filename: {} args: {:?}: envp: {:?}", + filename, args, envp + ); + + // clear memory map + // TODO: solve memory conflict + // task.pcb.lock().memset.retain(|x| x.mtype == MemType::PTE); + + // check exec file. + if filename == "/bin/true" { + self.task.exit(0); + return Ok(0); + } + let _exec_file = FileItem::fs_open(filename, OpenFlags::O_RDONLY).map_err(from_vfs)?; + exec_with_process(self.task.clone(), filename.to_string(), args, envp).await?; + self.task.before_run(); + Ok(0) + } + + pub async fn sys_clone( + &self, + flags: usize, // 复制 标志位 + stack: usize, // 指定新的栈,可以为 0, 0 不处理 + ptid: UserRef, // 父线程 id + tls: usize, // TLS线程本地存储描述符 + ctid: UserRef, // 子线程 id + ) -> SysResult { + let sig = flags & 0xff; + debug!( + "[task {}] sys_clone @ flags: {:#x}, stack: {:#x}, ptid: {}, tls: {:#x}, ctid: {}", + self.tid, flags, stack, ptid, tls, ctid + ); + let flags = CloneFlags::from_bits_truncate(flags); + debug!( + "[task {}] sys_clone @ flags: {:?}, stack: {:#x}, ptid: {}, tls: {:#x}, ctid: {}", + self.tid, flags, stack, ptid, tls, ctid + ); + + let new_task = match flags.contains(CloneFlags::CLONE_THREAD) { + true => self.task.clone().thread_clone(), + // false => curr_task.clone().fork(user_entry()), + // use cow(Copy On Write) to save memory. + false => self.task.clone().cow_fork(), + }; + + let clear_child_tid = if flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) { + ctid + } else { + UserRef::from(0) + }; + + let mut new_tcb = new_task.tcb.write(); + new_tcb.clear_child_tid = clear_child_tid.addr(); + + if stack != 0 { + new_tcb.cx[TrapFrameArgs::SP] = stack; + } + // set tls. + if flags.contains(CloneFlags::CLONE_SETTLS) { + new_tcb.cx[TrapFrameArgs::TLS] = tls; + } + if flags.contains(CloneFlags::CLONE_PARENT_SETTID) { + *ptid.get_mut() = new_task.task_id as _; + } + if flags.contains(CloneFlags::CLONE_CHILD_SETTID) && ctid.is_valid() { + *ctid.get_mut() = new_task.task_id as _; + } + new_tcb.exit_signal = sig as u8; + drop(new_tcb); + yield_now().await; + thread::spawn(new_task.clone(), user_entry()); + Ok(new_task.task_id) + } + + #[cfg(target_arch = "x86_64")] + pub async fn sys_fork(&self) -> SysResult { + warn!("transfer syscall_fork to syscall_clone"); + self.sys_clone(0x11, 0, 0.into(), 0, 0.into()).await + } + + pub async fn sys_wait4( + &self, + pid: isize, // 指定进程ID,可为-1等待任何子进程; + status: UserRef, // 接收状态的指针; + options: usize, // WNOHANG,WUNTRACED,WCONTINUED; + ) -> SysResult { + debug!( + "[task {}] sys_wait4 @ pid: {}, status: {}, options: {}", + self.tid, pid, status, options + ); + + // return LinuxError::ECHILD if there has no child process. + if self.task.inner_map(|inner| inner.children.len()) == 0 { + return Err(LinuxError::ECHILD); + } + + if pid != -1 { + self.task + .inner_map(|inner| { + inner + .children + .iter() + .find(|x| x.task_id == pid as usize) + .cloned() + }) + .ok_or(LinuxError::ECHILD)?; + } + if options == 0 || options == 2 || options == 3 || options == 10 { + debug!("children:{:?}", self.task.pcb.lock().children.len()); + let child_task = WaitPid(self.task.clone(), pid).await?; + + debug!( + "wait ok: {} waiter: {}", + child_task.task_id, self.task.task_id + ); + // release the task resources + self.task + .pcb + .lock() + .children + .retain(|x| x.task_id != child_task.task_id); + child_task.release(); + debug!("wait pid: {}", child_task.exit_code().unwrap()); + + if status.is_valid() { + *status.get_mut() = (child_task.exit_code().unwrap() as i32) << 8; + } + Ok(child_task.task_id) + } else if options == 1 { + let child_task = self + .task + .pcb + .lock() + .children + .iter() + .find(|x| x.task_id == pid as usize || pid == -1) + .cloned(); + let exit = child_task.clone().and_then(|x| x.exit_code()); + match exit { + Some(t1) => { + let child_task = child_task.unwrap(); + // Release task. + self.task + .pcb + .lock() + .children + .retain(|x| x.task_id != child_task.task_id); + child_task.release(); + if status.is_valid() { + *status.get_mut() = (t1 as i32) << 8; + } + // TIPS: This is a small change. + Ok(child_task.task_id) + // Ok(0) + } + None => Ok(0), + } + } else { + warn!("wait4 unsupported options: {}", options); + Err(LinuxError::EPERM) + } + } + + pub async fn sys_sched_yield(&self) -> SysResult { + debug!("sys_sched_yield @ "); + yield_now().await; + Ok(0) + } + + /// 对于每个线程,内核维护着两个属性(地址),分别称为set_child_tid和clear_child_tid。默认情况下,这两个属性包含值NULL。 + + /// set_child_tid + /// 如果使用带有CLONE_CHILD_SETTID标志的clone(2)启动线程,则set_child_tid设置为该系统调用的ctid参数中传递的值。 + /// 设置set_child_tid时,新线程要做的第一件事就是在该地址写入其线程ID。 + /// clear_child_tid + /// 如果使用带有CLONE_CHILD_CLEARTID标志的clone(2)启动线程,则clear_child_tid设置为该系统调用的ctid参数中传递的值。 + /// 系统调用set_tid_address()将调用线程的clear_child_tid值设置为tidptr。 + + // 当clear_child_tid不为NULL的线程终止时,如果该线程与其他线程共享内存,则将0写入clear_child_tid中指定的地址,并且内核执行以下操作: + + // futex(clear_child_tid,FUTEX_WAKE,1 , NULL,NULL,0); + + // 此操作的效果是唤醒正在执行内存位置上的futex等待的单个线程。来自futex唤醒操作的错误将被忽略。 + pub async fn sys_set_tid_address(&self, tid_ptr: usize) -> SysResult { + // information source: https://www.onitroad.com/jc/linux/man-pages/linux/man2/set_tid_address.2.html + + debug!("sys_set_tid_address @ tid_ptr: {:#x}", tid_ptr); + self.task.tcb.write().clear_child_tid = tid_ptr; + Ok(self.tid) + } + + /// sys_getpid() 获取进程 id + pub async fn sys_getpid(&self) -> SysResult { + Ok(self.task.process_id) + } + + /// sys_getppid() 获取父进程 id + pub async fn sys_getppid(&self) -> SysResult { + debug!("sys_getppid @ "); + self.task + .parent + .read() + .upgrade() + .map(|x| x.task_id) + .ok_or(LinuxError::EPERM) + } + + /// sys_gettid() 获取线程 id. + /// need to write correct clone and thread_clone for pthread. + pub async fn sys_gettid(&self) -> SysResult { + debug!("sys_gettid @ "); + Ok(self.tid) + } + + pub async fn sys_futex( + &self, + uaddr_ptr: UserRef, + op: usize, + value: usize, + value2: usize, + uaddr2: usize, + value3: usize, + ) -> SysResult { + let op = if op >= 0x80 { op - 0x80 } else { op }; + debug!( + "[task {}] sys_futex @ uaddr: {} op: {} value: {:#x}, value2: {:#x}, uaddr2: {:#x} , value3: {:#x}", + self.tid, uaddr_ptr, op, value, value2, uaddr2, value3 + ); + let uaddr = uaddr_ptr.get_mut(); + let flags = FromPrimitive::from_usize(op).ok_or(LinuxError::EINVAL)?; + debug!( + "sys_futex @ uaddr: {:#x} flags: {:?} value: {}", + uaddr, flags, value + ); + + match flags { + FutexFlags::Wait => { + if *uaddr == value as _ { + let futex_table = self.task.pcb.lock().futex_table.clone(); + let mut table = futex_table.lock(); + match table.get_mut(&uaddr_ptr.addr()) { + Some(t) => t.push(self.tid), + None => { + table.insert(uaddr_ptr.addr(), vec![self.tid]); + } + } + drop(table); + let wait_func = WaitFutex(futex_table.clone(), self.tid); + if value2 != 0 { + let timeout = UserRef::::from(value2).get_mut(); + match select(wait_func, WaitUntilsec(current_nsec() + timeout.to_nsec())) + .await + { + executor::Either::Left((res, _)) => res, + executor::Either::Right(_) => Err(LinuxError::ETIMEDOUT), + } + } else { + wait_func.await + } + // wait_func.await + } else { + Err(LinuxError::EAGAIN) + } + } + FutexFlags::Wake => { + let futex_table = self.task.pcb.lock().futex_table.clone(); + let count = futex_wake(futex_table, uaddr_ptr.addr(), value); + yield_now().await; + Ok(count) + } + FutexFlags::Requeue => { + let futex_table = self.task.pcb.lock().futex_table.clone(); + Ok(futex_requeue( + futex_table, + uaddr_ptr.addr(), + value, + uaddr2, + value2, + )) + } + _ => Err(LinuxError::EPERM), + } + } + + pub async fn sys_tkill(&self, tid: usize, signum: usize) -> SysResult { + debug!("sys_tkill @ tid: {}, signum: {}", tid, signum); + let mut child = self.task.inner_map(|x| { + x.threads + .iter() + .find(|x| match x.upgrade() { + Some(thread) => thread.task_id == tid, + None => false, + }) + .cloned() + }); + + if tid == self.tid { + child = Some(Arc::downgrade(&self.task)); + } + + match child { + Some(child) => { + let target_signal = SignalFlags::from_usize(signum); + let child_task = child.upgrade().unwrap(); + let mut child_tcb = child_task.tcb.write(); + if !child_tcb.signal.has_sig(target_signal.clone()) { + child_tcb.signal.add_signal(target_signal); + } else if let Some(index) = target_signal.real_time_index() { + child_tcb.signal_queue[index] += 1; + } + // let signal = child + // .upgrade().unwrap() + // .tcb + // .write() + // .signal + // .add_signal(SignalFlags::from_usize(signum)); + Ok(0) + } + None => Err(LinuxError::ECHILD), + } + } + + pub async fn sys_sigreturn(&self) -> SysResult { + debug!("sys_sigreturn @ "); + Ok(0) + } + + pub async fn sys_getrusage(&self, who: usize, usage_ptr: UserRef) -> SysResult { + debug!("sys_getrusgae @ who: {}, usage_ptr: {}", who, usage_ptr); + // let Rusage + let rusage = usage_ptr.get_mut(); + + let tms = self.task.inner_map(|inner| inner.tms); + let stime = Time::from_raw(tms.stime as _); + let utime = Time::from_raw(tms.utime as _); + rusage.ru_stime = TimeVal { + sec: stime.to_usec() / 1_000_000, + usec: stime.to_usec() % 1_000_000, + }; + rusage.ru_utime = TimeVal { + sec: utime.to_usec() / 1_000_000, + usec: utime.to_usec() % 1_000_000, + }; + Ok(0) + } + + pub fn sys_exit_group(&self, exit_code: usize) -> SysResult { + debug!("sys_exit_group @ exit_code: {}", exit_code); + // let children = user_task.pcb.lock().children.clone(); + // for ctask in children.iter().filter(|x| x.task_id != user_task.task_id) { + // ctask.exit(exit_code); + // } + self.task.exit(exit_code); + Ok(0) + // Err(LinuxError::EPERM) + } + + pub async fn sys_kill(&self, pid: usize, signum: usize) -> SysResult { + let signal = SignalFlags::from_usize(signum); + debug!( + "[task {}] sys_kill @ pid: {}, signum: {:?}", + self.tid, pid, signal + ); + + let user_task = match tid2task(pid) { + Some(task) => task + .downcast_arc::() + .map_err(|_| LinuxError::ESRCH), + None => Err(LinuxError::ESRCH), + }?; + + user_task.tcb.write().signal.add_signal(signal.clone()); + + yield_now().await; + + Ok(0) + } + + pub async fn sys_setsid(&self) -> SysResult { + debug!("[task {}] sys_setsid", self.tid); + let parent = self.task.parent.read().clone(); + + if let Some(parent) = parent.upgrade() { + parent.pcb.lock().children.retain(|x| x.task_id != self.tid); + *self.task.parent.write() = Weak::::new(); + } + Ok(0) + } + + pub async fn sys_sched_getaffinity( + &self, + pid: usize, + cpu_set_size: usize, + mask: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_sched_getaffinity @ pid: {} cpu_set_size: {}, mask: {:#x?}", + self.tid, pid, cpu_set_size, mask + ); + // TODO: + Ok(0) + } +} diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs new file mode 100644 index 00000000..8d392dba --- /dev/null +++ b/kernel/src/syscall/time.rs @@ -0,0 +1,194 @@ +use core::{ + future::Future, + ops::Add, + pin::Pin, + task::{Context, Poll}, +}; + +use executor::select; +use fs::TimeSpec; +pub use hal::current_nsec; +use hal::{ITimerVal, TimeVal}; +use log::{debug, warn}; +use polyhal::time::Time; + +use crate::{ + tasks::{WaitHandleAbleSignal, TMS}, + user::UserTaskContainer, +}; + +use super::{ + consts::{LinuxError, UserRef}, + SysResult, +}; +impl UserTaskContainer { + pub async fn sys_gettimeofday( + &self, + tv_ptr: UserRef, + timezone_ptr: usize, + ) -> SysResult { + debug!( + "sys_gettimeofday @ tv_ptr: {}, timezone: {:#x}", + tv_ptr, timezone_ptr + ); + *tv_ptr.get_mut() = TimeVal::now(); + Ok(0) + } + + pub async fn sys_nanosleep( + &self, + req_ptr: UserRef, + rem_ptr: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_nanosleep @ req_ptr: {}, rem_ptr: {}", + self.tid, req_ptr, rem_ptr + ); + let ns = current_nsec(); + let req = req_ptr.get_mut(); + debug!("nano sleep {} nseconds", req.sec * 1_000_000_000 + req.nsec); + + let res = match select( + WaitHandleAbleSignal(self.task.clone()), + WaitUntilsec(ns + req.sec * 1_000_000_000 + req.nsec), + ) + .await + { + executor::Either::Right(_) => Ok(0), + executor::Either::Left(_) => Err(LinuxError::EINTR), + }; + if rem_ptr.is_valid() { + *rem_ptr.get_mut() = Default::default(); + } + res + } + + pub async fn sys_times(&self, tms_ptr: UserRef) -> SysResult { + debug!("sys_times @ tms: {}", tms_ptr); + self.task.inner_map(|x| *tms_ptr.get_mut() = x.tms); + Ok(Time::now().raw()) + } + + pub async fn sys_clock_gettime( + &self, + clock_id: usize, + times_ptr: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_clock_gettime @ clock_id: {}, times_ptr: {}", + self.tid, clock_id, times_ptr + ); + + let ns = match clock_id { + 0 => current_nsec(), // CLOCK_REALTIME + 1 => Time::now().to_nsec(), // CLOCK_MONOTONIC + 2 => { + warn!("CLOCK_PROCESS_CPUTIME_ID not implemented"); + 0 + } + 3 => { + warn!("CLOCK_THREAD_CPUTIME_ID not implemented"); + 0 + } + _ => return Err(LinuxError::EINVAL), + }; + + *times_ptr.get_mut() = TimeSpec { + sec: ns / 1_000_000_000, + nsec: ns % 1_000_000_000, + }; + Ok(0) + } + + #[inline] + pub async fn sys_clock_getres( + &self, + clock_id: usize, + times_ptr: UserRef, + ) -> SysResult { + debug!("clock_getres @ {} {:#x?}", clock_id, times_ptr); + if times_ptr.is_valid() { + *times_ptr.get_mut() = TimeSpec { sec: 0, nsec: 1 }; + } + Ok(0) + } + pub async fn sys_setitimer( + &self, + which: usize, + times_ptr: UserRef, + old_timer_ptr: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_setitimer @ which: {} times_ptr: {} old_timer_ptr: {}", + self.tid, which, times_ptr, old_timer_ptr + ); + + if which == 0 { + let mut pcb = self.task.pcb.lock(); + if old_timer_ptr.is_valid() { + *old_timer_ptr.get_mut() = pcb.timer[0].timer; + } + + if times_ptr.is_valid() { + let new_timer = times_ptr.get_ref(); + pcb.timer[0].timer = *new_timer; + pcb.timer[0].next = TimeVal::now().add(pcb.timer[0].timer.value); + if new_timer.value.sec == 0 && new_timer.value.usec == 0 { + pcb.timer[0].next = Default::default(); + pcb.timer[0].last = Default::default(); + } + } + Ok(0) + } else { + Err(LinuxError::EPERM) + } + } + + pub async fn sys_clock_nanosleep( + &self, + clock_id: usize, + flags: usize, + req_ptr: UserRef, + rem_ptr: UserRef, + ) -> SysResult { + debug!( + "[task {}] sys_clock_nanosleep @ clock_id: {}, flags: {:#x} req_ptr: {}, rem_ptr: {}", + self.tid, clock_id, flags, req_ptr, rem_ptr + ); + + if flags == 1 { + let req = req_ptr.get_mut(); + WaitUntilsec(req.sec * 1_000_000_000 + req.nsec).await; + if rem_ptr.is_valid() { + *rem_ptr.get_mut() = Default::default(); + } + } else { + let ns = current_nsec(); + let req = req_ptr.get_mut(); + debug!("nano sleep {} nseconds", req.sec * 1_000_000_000 + req.nsec); + WaitUntilsec(ns + req.sec * 1_000_000_000 + req.nsec).await; + } + + Ok(0) + } +} + +pub struct WaitUntilsec(pub usize); + +impl Future for WaitUntilsec { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let ns = current_nsec(); + + match ns > self.0 { + true => Poll::Ready(()), + false => Poll::Pending, + } + } +} + +#[allow(dead_code)] +pub fn wait_ms(ms: usize) -> WaitUntilsec { + WaitUntilsec(current_nsec() + ms * 0x1000_0000) +} diff --git a/kernel/src/tasks/async_ops.rs b/kernel/src/tasks/async_ops.rs new file mode 100644 index 00000000..e497feb5 --- /dev/null +++ b/kernel/src/tasks/async_ops.rs @@ -0,0 +1,146 @@ +use core::{cmp, future::Future, pin::Pin, task::Poll}; + +use alloc::{sync::Arc, vec::Vec}; +use executor::AsyncTask; +use polyhal::time::Time; +use sync::Mutex; + +use crate::syscall::consts::LinuxError; + +use super::{ + current_user_task, + task::{FutexTable, UserTask}, +}; + +pub struct NextTick(usize); + +impl Future for NextTick { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> Poll { + let curr = Time::now().to_msec(); + if curr < self.0 { + Poll::Pending + } else { + Poll::Ready(()) + } + } +} + +pub struct WaitPid(pub Arc, pub isize); + +impl Future for WaitPid { + type Output = Result, LinuxError>; + + fn poll(self: Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> Poll { + let inner = self.0.pcb.lock(); + let res = inner + .children + .iter() + .find(|x| (self.1 == -1 || x.task_id == self.1 as usize) && x.exit_code().is_some()) + .cloned(); + drop(inner); + match res { + Some(task) => Poll::Ready(Ok(task.clone())), + None => Poll::Pending, + } + } +} + +pub struct WaitSignal(pub Arc); + +impl Future for WaitSignal { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> Poll { + match self.0.tcb.read().signal.has_signal() { + true => Poll::Ready(()), + false => Poll::Pending, + } + } +} + +pub fn in_futex(futex_table: Arc>, task_id: usize) -> bool { + let futex_table = futex_table.lock(); + futex_table.values().any(|x| x.contains(&task_id)) +} + +pub struct WaitFutex(pub Arc>, pub usize); + +impl Future for WaitFutex { + type Output = Result; + + fn poll(self: Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> Poll { + let signal = current_user_task().tcb.read().signal.clone(); + match in_futex(self.0.clone(), self.1) { + true => { + if signal.has_signal() { + if let Some(x) = self.0.lock().values_mut().find(|x| x.contains(&self.1)) { + x.retain(|x| *x != self.1) + } + Poll::Ready(Err(LinuxError::EINTR)) + } else { + Poll::Pending + } + } + false => Poll::Ready(Ok(0)), + } + } +} + +pub struct WaitHandleAbleSignal(pub Arc); + +impl Future for WaitHandleAbleSignal { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut core::task::Context<'_>) -> Poll { + let task = &self.0; + let sig_mask = task.tcb.read().sigmask; + let has_signal = task.tcb.read().signal.mask(sig_mask).has_signal(); + + match has_signal { + true => Poll::Ready(()), + false => Poll::Pending, + } + } +} + +pub fn futex_wake(futex_table: Arc>, uaddr: usize, wake_count: usize) -> usize { + let mut futex_table = futex_table.lock(); + let que_size = futex_table.get_mut(&uaddr).map(|x| x.len()).unwrap_or(0); + if que_size == 0 { + 0 + } else { + let que = futex_table + .get_mut(&uaddr) + .map(|x| x.drain(..cmp::min(wake_count, que_size))); + + que.map(|x| x.count()).unwrap_or(0) + } +} + +pub fn futex_requeue( + futex_table: Arc>, + uaddr: usize, + wake_count: usize, + uaddr2: usize, + reque_count: usize, +) -> usize { + let mut futex_table = futex_table.lock(); + + let waked_size = futex_table + .get_mut(&uaddr) + .map(|x| x.drain(..wake_count).count()) + .unwrap_or(0); + + let reque: Option> = futex_table + .get_mut(&uaddr) + .map(|x| x.drain(..reque_count).collect()); + + if let Some(reque) = reque { + futex_table.entry(uaddr2).or_default(); + futex_table.get_mut(&uaddr2).unwrap().extend(reque); + } + + waked_size +} diff --git a/kernel/src/tasks/elf.rs b/kernel/src/tasks/elf.rs new file mode 100644 index 00000000..a60ac0d4 --- /dev/null +++ b/kernel/src/tasks/elf.rs @@ -0,0 +1,199 @@ +use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec}; +use devices::PAGE_SIZE; +use executor::AsyncTask; +use log::warn; +use polyhal::{ + addr::VirtPage, + trapframe::{TrapFrame, TrapFrameArgs}, +}; +use xmas_elf::{ + program::Type, + sections::SectionData, + symbol_table::{DynEntry64, Entry}, + ElfFile, +}; + +use crate::syscall::consts::{elf, LinuxError}; +use crate::tasks::memset::MemType; + +use super::task::UserTask; + +pub trait ElfExtra { + fn get_ph_addr(&self) -> Result; + fn dynsym(&self) -> Result<&[DynEntry64], &'static str>; + fn relocate(&self, base: usize) -> Result, &str>; +} + +impl ElfExtra for ElfFile<'_> { + // 获取elf加载需要的内存大小 + fn get_ph_addr(&self) -> Result { + if let Some(phdr) = self + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Phdr)) + { + // if phdr exists in program header, use it + Ok(phdr.virtual_addr()) + } else if let Some(elf_addr) = self + .program_iter() + .find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) + { + // otherwise, check if elf is loaded from the beginning, then phdr can be inferred. + Ok(elf_addr.virtual_addr() + self.header.pt2.ph_offset()) + } else { + warn!("elf: no phdr found, tls might not work"); + Err(LinuxError::EBADF) + } + } + + fn dynsym(&self) -> Result<&[DynEntry64], &'static str> { + match self + .find_section_by_name(".dynsym") + .ok_or(".dynsym not found")? + .get_data(self) + .map_err(|_| "corrupted .dynsym")? + { + SectionData::DynSymbolTable64(dsym) => Ok(dsym), + _ => Err("bad .dynsym"), + } + } + + fn relocate(&self, base: usize) -> Result, &str> { + let mut res = vec![]; + let data = self + .find_section_by_name(".rela.dyn") + .ok_or(".rela.dyn not found")? + .get_data(self) + .map_err(|_| "corrupted .rela.dyn")?; + let entries = match data { + SectionData::Rela64(entries) => entries, + _ => return Err("bad .rela.dyn"), + }; + let dynsym = self.dynsym()?; + for entry in entries.iter() { + const REL_GOT: u32 = 6; + const REL_PLT: u32 = 7; + const REL_RELATIVE: u32 = 8; + const R_RISCV_64: u32 = 2; + const R_RISCV_RELATIVE: u32 = 3; + const R_AARCH64_RELATIVE: u32 = 0x403; + const R_AARCH64_GLOBAL_DATA: u32 = 0x401; + + match entry.get_type() { + REL_GOT | REL_PLT | R_RISCV_64 | R_AARCH64_GLOBAL_DATA => { + let dynsym = &dynsym[entry.get_symbol_table_index() as usize]; + let symval = if dynsym.shndx() == 0 { + let name = dynsym.get_name(self)?; + panic!("need to find symbol: {:?}", name); + } else { + base + dynsym.value() as usize + }; + let value = symval + entry.get_addend() as usize; + let addr = base + entry.get_offset() as usize; + // vmar.write_memory(addr, &value.to_ne_bytes()) + // .map_err(|_| "Invalid Vmar")?; + res.push((addr, value)) + } + REL_RELATIVE | R_RISCV_RELATIVE | R_AARCH64_RELATIVE => { + let value = base + entry.get_addend() as usize; + let addr = base + entry.get_offset() as usize; + // vmar.write_memory(addr, &value.to_ne_bytes()) + // .map_err(|_| "Invalid Vmar")?; + res.push((addr, value)) + } + t => unimplemented!("unknown type: {}", t), + } + } + // panic!("STOP"); + Ok(res) + } +} + +#[allow(clippy::too_many_arguments)] +pub fn init_task_stack( + user_task: Arc, + args: Vec, + base: usize, + path: &str, + entry_point: usize, + ph_count: usize, + ph_entry_size: usize, + ph_addr: usize, + heap_bottom: usize, + tls: usize, +) { + // map stack + user_task.frame_alloc(VirtPage::from_addr(0x7ffe0000), MemType::Stack, 32); + log::debug!( + "[task {}] entry: {:#x}", + user_task.get_task_id(), + base + entry_point + ); + user_task.inner_map(|inner| { + inner.heap = heap_bottom; + inner.entry = base + entry_point; + }); + + let mut tcb = user_task.tcb.write(); + + tcb.cx = TrapFrame::new(); + tcb.cx[TrapFrameArgs::SP] = 0x8000_0000; // stack top; + tcb.cx[TrapFrameArgs::SEPC] = base + entry_point; + tcb.cx[TrapFrameArgs::TLS] = tls; + + drop(tcb); + + // push stack + let envp = vec![ + "LD_LIBRARY_PATH=/", + "PS1=\x1b[1m\x1b[32mByteOS\x1b[0m:\x1b[1m\x1b[34m\\w\x1b[0m\\$ \0", + "PATH=/:/bin:/usr/bin", + "UB_BINDIR=./", + ]; + let envp: Vec = envp + .into_iter() + .rev() + .map(|x| user_task.push_str(x)) + .collect(); + let args: Vec = args + .into_iter() + .rev() + .map(|x| user_task.push_str(&x)) + .collect(); + + let random_ptr = user_task.push_arr(&[0u8; 16]); + let mut auxv = BTreeMap::new(); + auxv.insert(elf::AT_PLATFORM, user_task.push_str("riscv")); + auxv.insert(elf::AT_EXECFN, user_task.push_str(path)); + // auxv.insert(elf::AT_PHNUM, elf_header.pt2.ph_count() as usize); + auxv.insert(elf::AT_PHNUM, ph_count); + auxv.insert(elf::AT_PAGESZ, PAGE_SIZE); + auxv.insert(elf::AT_ENTRY, base + entry_point); + // auxv.insert(elf::AT_PHENT, elf_header.pt2.ph_entry_size() as usize); + auxv.insert(elf::AT_PHENT, ph_entry_size); + // auxv.insert(elf::AT_PHDR, base + elf.get_ph_addr().unwrap_or(0) as usize); + auxv.insert(elf::AT_PHDR, base + ph_addr); + auxv.insert(elf::AT_GID, 0); + auxv.insert(elf::AT_EGID, 0); + auxv.insert(elf::AT_UID, 0); + auxv.insert(elf::AT_EUID, 0); + auxv.insert(elf::AT_SECURE, 0); + auxv.insert(elf::AT_RANDOM, random_ptr); + + // auxv top + user_task.push_num(0); + // TODO: push auxv + auxv.iter().for_each(|(key, v)| { + user_task.push_num(*v); + user_task.push_num(*key); + }); + + user_task.push_num(0); + envp.iter().for_each(|x| { + user_task.push_num(*x); + }); + user_task.push_num(0); + args.iter().for_each(|x| { + user_task.push_num(*x); + }); + user_task.push_num(args.len()); +} diff --git a/kernel/src/tasks/filetable.rs b/kernel/src/tasks/filetable.rs new file mode 100644 index 00000000..6d8aa154 --- /dev/null +++ b/kernel/src/tasks/filetable.rs @@ -0,0 +1,400 @@ +use core::{ + mem::size_of, + ops::{Deref, DerefMut}, +}; + +use alloc::{string::String, sync::Arc, vec::Vec}; +use fs::{ + dentry::{self, dentry_open, dentry_root, DentryNode}, + INodeInterface, VfsError, WaitBlockingRead, WaitBlockingWrite, +}; +use sync::Mutex; +use vfscore::{ + DirEntry, Dirent64, Metadata, OpenFlags, PollEvent, SeekFrom, Stat, StatFS, TimeSpec, +}; + +const FILE_MAX: usize = 255; +const FD_NONE: Option> = Option::None; + +#[derive(Clone)] +pub struct FileTable(pub Vec>>); + +impl FileTable { + pub fn new() -> Self { + let mut file_table: Vec>> = vec![FD_NONE; FILE_MAX]; + file_table[..3].fill(Some( + FileItem::fs_open("/dev/ttyv0", OpenFlags::O_RDWR).expect("can't read tty file"), + )); + Self(file_table) + } +} + +impl Deref for FileTable { + type Target = Vec>>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for FileTable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +pub fn rlimits_new() -> Vec { + let mut rlimits = vec![0usize; 8]; + rlimits[7] = FILE_MAX; + rlimits +} + +bitflags! { + #[derive(Clone, Debug)] + pub struct FileOptions: u8 { + /// Hangup. + const R = 1; + const W = 1 << 1; + const X = 1 << 3; + /// Create file. + const C = 1 << 4; + } +} + +impl Default for FileOptions { + fn default() -> Self { + FileOptions::R | FileOptions::W | FileOptions::X + } +} + +pub struct FileItem { + pub inner: Arc, + pub dentry: Option>, + pub options: FileOptions, + pub offset: Mutex, + pub flags: Mutex, +} + +impl FileItem { + pub fn new( + inner: Arc, + dentry: Option>, + options: FileOptions, + ) -> Arc { + Arc::new(Self { + inner, + options, + dentry, + offset: Mutex::new(0), + flags: Mutex::new(OpenFlags::NONE), + }) + } + + /// Get root directory FileItem. + pub fn root() -> Arc { + let dentry = dentry_root(); + Self::new( + dentry.node.clone(), + Some(dentry), + FileOptions::R | FileOptions::W, + ) + } + + pub fn new_dev(inner: Arc) -> Arc { + Arc::new(Self { + inner, + offset: Mutex::new(0), + dentry: None, + options: FileOptions::default(), + flags: Mutex::new(OpenFlags::NONE), + }) + } + + pub fn get_bare_file(&self) -> Arc { + self.inner.clone() + } + + pub fn fs_open(path: &str, open_flags: OpenFlags) -> Result, VfsError> { + let mut options = FileOptions::R | FileOptions::X; + if open_flags.contains(OpenFlags::O_WRONLY) + || open_flags.contains(OpenFlags::O_RDWR) + || open_flags.contains(OpenFlags::O_ACCMODE) + { + options = options.union(FileOptions::W); + } + let dentry_node = dentry::dentry_open(dentry_root(), path, OpenFlags::NONE)?; + let offset = if open_flags.contains(OpenFlags::O_APPEND) { + dentry_node.node.metadata()?.size + } else { + 0 + }; + Ok(Arc::new(Self { + inner: dentry_node.node.clone(), + options, + dentry: Some(dentry_node), + offset: Mutex::new(offset), + flags: Mutex::new(open_flags), + })) + } + + pub fn dentry_open(&self, path: &str, flags: OpenFlags) -> Result, VfsError> { + let mut options = FileOptions::R | FileOptions::X; + if flags.contains(OpenFlags::O_WRONLY) + || flags.contains(OpenFlags::O_RDWR) + || flags.contains(OpenFlags::O_ACCMODE) + { + options = options.union(FileOptions::W); + } + assert!(self.dentry.is_some()); + dentry_open(self.dentry.clone().unwrap(), path, flags.clone()).map(|x| { + Arc::new(FileItem { + inner: x.node.clone(), + dentry: Some(x), + offset: Mutex::new(0), + flags: Mutex::new(flags.clone()), + options, + }) + }) + } + + #[inline(always)] + fn check_writeable(&self) -> Result<(), VfsError> { + if self.options.contains(FileOptions::W) { + Ok(()) + } else { + Err(VfsError::NotWriteable) + } + } + + pub fn path(&self) -> Result { + // Ok(&self.path) + // dentry_open(dentry, path, flags) + match &self.dentry { + Some(dentry) => Ok(dentry.path()), + None => Err(VfsError::NotFile), + } + } + + pub fn getdents(&self, buffer: &mut [u8]) -> Result { + let buf_ptr = buffer.as_mut_ptr() as usize; + let len = buffer.len(); + let mut ptr: usize = buf_ptr; + let mut finished = 0; + for (i, x) in self + .read_dir()? + .iter() + .enumerate() + .skip(*self.offset.lock()) + { + let filename = &x.filename; + let file_bytes = filename.as_bytes(); + let current_len = size_of::() + file_bytes.len() + 1; + if len - (ptr - buf_ptr) < current_len { + break; + } + + // let dirent = c2rust_ref(ptr as *mut Dirent); + let dirent: &mut Dirent64 = unsafe { (ptr as *mut Dirent64).as_mut() }.unwrap(); + + dirent.ino = 0; + dirent.off = current_len as i64; + dirent.reclen = current_len as u16; + + dirent.ftype = 0; // 0 ftype is file + + let buffer = unsafe { + core::slice::from_raw_parts_mut(dirent.name.as_mut_ptr(), file_bytes.len() + 1) + }; + buffer[..file_bytes.len()].copy_from_slice(file_bytes); + buffer[file_bytes.len()] = b'\0'; + ptr += current_len; + finished = i + 1; + } + *self.offset.lock() = finished; + Ok(ptr - buf_ptr) + } +} + +#[allow(dead_code)] +impl FileItem { + pub fn mkdir(&self, name: &str) -> Result, VfsError> { + self.inner.mkdir(name) + } + + pub fn rmdir(&self, name: &str) -> Result<(), VfsError> { + self.inner.rmdir(name) + } + + pub fn remove(&self, name: &str) -> Result<(), VfsError> { + self.inner.remove(name) + } + + pub fn moveto(&self, _path: &str) -> Result { + todo!("Move the file? to other location") + } + + pub fn remove_self(&self) -> Result<(), VfsError> { + match &self.dentry { + Some(dentry) => { + let filename = &dentry.filename; + if let Some(parent) = dentry.parent.upgrade() { + parent.node.remove(filename)?; + parent.children.lock().retain(|x| &x.filename != filename); + } + Ok(()) + } + None => Err(VfsError::FileNotFound), + } + } + + pub fn touch(&self, name: &str) -> Result, VfsError> { + self.inner.touch(name) + } + + pub fn read_dir(&self) -> Result, VfsError> { + self.inner.read_dir() + } + + pub fn metadata(&self) -> Result { + self.inner.metadata() + } + + pub fn lookup(&self, name: &str) -> Result, VfsError> { + self.inner.lookup(name) + } + + pub fn open(&self, name: &str, flags: OpenFlags) -> Result, VfsError> { + self.inner.open(name, flags) + } + + pub fn ioctl(&self, command: usize, arg: usize) -> Result { + self.inner.ioctl(command, arg) + } + + pub fn truncate(&self, size: usize) -> Result<(), VfsError> { + // self.check_writeable()?; + // let mut offset = self.offset.lock(); + // if *offset > size { + // *offset = size; + // } + self.inner.truncate(size) + } + + pub fn flush(&self) -> Result<(), VfsError> { + self.inner.flush() + } + + pub fn resolve_link(&self) -> Result { + self.inner.resolve_link() + } + + pub fn link(&self, name: &str, src: Arc) -> Result<(), VfsError> { + self.inner.link(name, src) + } + + pub fn unlink(&self, name: &str) -> Result<(), VfsError> { + self.inner.unlink(name) + } + + pub fn stat(&self, stat: &mut Stat) -> Result<(), VfsError> { + self.inner.stat(stat)?; + stat.dev = 0; + Ok(()) + } + + pub fn mount(&self, path: &str) -> Result<(), VfsError> { + self.inner.mount(path) + } + + pub fn umount(&self) -> Result<(), VfsError> { + self.inner.umount() + } + + pub fn statfs(&self, statfs: &mut StatFS) -> Result<(), VfsError> { + self.inner.statfs(statfs) + } + + pub fn utimes(&self, times: &mut [TimeSpec]) -> Result<(), VfsError> { + self.inner.utimes(times) + } + + pub fn poll(&self, events: PollEvent) -> Result { + self.inner.poll(events) + } +} + +impl FileItem { + pub fn readat(&self, offset: usize, buffer: &mut [u8]) -> Result { + self.inner.readat(offset, buffer) + } + + pub fn writeat(&self, offset: usize, buffer: &[u8]) -> Result { + self.check_writeable()?; + if buffer.is_empty() { + return Ok(0); + } + self.inner.writeat(offset, buffer) + } + + pub fn read(&self, buffer: &mut [u8]) -> Result { + let offset = *self.offset.lock(); + self.inner.readat(offset, buffer).map(|x| { + *self.offset.lock() += x; + x + }) + } + + pub fn write(&self, buffer: &[u8]) -> Result { + self.check_writeable()?; + if buffer.is_empty() { + return Ok(0); + } + let offset = *self.offset.lock(); + self.inner.writeat(offset, buffer).map(|x| { + *self.offset.lock() += x; + x + }) + } + + pub async fn async_read(&self, buffer: &mut [u8]) -> Result { + let offset = *self.offset.lock(); + if self.flags.lock().contains(OpenFlags::O_NONBLOCK) { + self.inner.readat(offset, buffer) + } else { + WaitBlockingRead(self.inner.clone(), buffer, offset).await + } + .map(|x| { + *self.offset.lock() += x; + x + }) + } + + pub async fn async_write(&self, buffer: &[u8]) -> Result { + // self.check_writeable()?; + if buffer.is_empty() { + return Ok(0); + } + let offset = *self.offset.lock(); + WaitBlockingWrite(self.inner.clone(), buffer, offset) + .await + .map(|x| { + *self.offset.lock() += x; + x + }) + } + + pub fn seek(&self, seek_from: SeekFrom) -> Result { + let offset = *self.offset.lock(); + let mut new_off = match seek_from { + SeekFrom::SET(off) => off as isize, + SeekFrom::CURRENT(off) => offset as isize + off, + SeekFrom::END(off) => self.metadata()?.size as isize + off, + }; + if new_off < 0 { + new_off = 0; + } + // assert!(new_off >= 0); + *self.offset.lock() = new_off as _; + Ok(new_off as _) + } +} diff --git a/kernel/src/tasks/initproc.rs b/kernel/src/tasks/initproc.rs new file mode 100644 index 00000000..da895138 --- /dev/null +++ b/kernel/src/tasks/initproc.rs @@ -0,0 +1,407 @@ +#![allow(dead_code)] +#![allow(unused_imports)] +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; +use executor::{current_task, release_task, task::TaskType, tid2task, yield_now, TASK_MAP}; +use frame_allocator::get_free_pages; +use fs::{ + dentry::{dentry_open, dentry_root, DentryNode}, + get_filesystem, File, FileType, OpenFlags, +}; +use log::debug; +use logging::get_char; +use polyhal::{debug_console::DebugConsole, instruction::shutdown}; +use vfscore::INodeInterface; + +use crate::tasks::add_user_task; + +use super::UserTask; + +const LF: u8 = b'\n'; +const CR: u8 = b'\r'; +const DL: u8 = b'\x7f'; +const BS: u8 = b'\x08'; +const SPACE: u8 = b' '; + +fn help() { + println!("help"); + println!("ls"); + println!("clear"); + println!("exit"); +} + +fn list_files(file: File, space: usize) { + for i in file.read_dir().expect("can't read dir") { + println!("{:<3$}{} {}", "", i.filename, i.len, space); + if i.file_type == FileType::Directory { + list_files( + file.open(&i.filename, OpenFlags::O_RDWR) + .expect("can't read dir"), + space + 4, + ); + } + } +} + +fn clear() { + DebugConsole::putchar(0x1b); + DebugConsole::putchar(0x5b); + DebugConsole::putchar(0x48); + DebugConsole::putchar(0x1b); + DebugConsole::putchar(0x5b); + DebugConsole::putchar(0x32); + DebugConsole::putchar(0x4a); +} + +async fn kill_all_tasks() { + TASK_MAP.lock().values().for_each(|task| { + task.upgrade().inspect(|x| { + if x.get_task_type() == TaskType::MonolithicTask { + x.exit(100) + } + }); + }); +} + +async fn run_libc_test() -> bool { + let commands = ["./runtest.exe -w entry-static.exe socket"]; + + for i in commands { + file_command(i).await + } + + false +} + +async fn run_all() -> bool { + let commands = [ + "brk", + "chdir", + "clone", + "close", + "dup", + "dup2", + "execve", + "exit", + "fork", + "fstat", + "getcwd", + "getpid", + "getppid", + "gettimeofday", + "mkdir_", + "mmap", + "mount /dev/sda ./mnt", + "munmap", + "open", + "times", + "openat", + "pipe", + "read", + "sleep", + "umount /dev/sda ./mnt", + "uname", + "unlink", + "wait", + "waitpid", + "getdents", + "write", + "yield", + ]; + + for i in commands { + file_command(i).await + } + + true +} + +async fn file_command(cmd: &str) { + let mut args: Vec<&str> = cmd.split(' ').filter(|x| !x.is_empty()).collect(); + debug!("cmd: {} args: {:?}", cmd, args); + let filename = args.drain(..1).last().unwrap(); + let filename = match filename.starts_with('/') { + true => String::from(filename), + false => String::from("/") + filename, + }; + match dentry_open(dentry_root(), &filename, OpenFlags::O_RDONLY) { + Ok(_) => { + info!("exec: {}", filename); + let mut args_extend = vec![filename.as_str()]; + args_extend.extend(args.into_iter()); + // args.into_iter().for_each(|x| args_extend.push(x)); + let task_id = add_user_task(&filename, args_extend, Vec::new()).await; + let task = tid2task(task_id).unwrap(); + loop { + if task.exit_code().is_some() { + release_task(task_id); + break; + } + yield_now().await; + } + // syscall(SYS_WAIT4, [0,0,0,0,0,0,0]) + // .await + // .expect("can't wait a pid"); + } + Err(_) => { + println!("unknown command: {}", cmd); + } + } +} + +pub async fn command(cmd: &str) -> bool { + match cmd.trim() { + "" => {} + "help" => help(), + "ls" => list_files( + dentry_open(dentry_root(), "/", OpenFlags::O_DIRECTORY) + .expect("can't find mount point at .") + .node + .clone(), + 0, + ), + "clear" => clear(), + "exit" => return true, + "run_all" => return run_all().await, + _ => file_command(cmd).await, + } + + false +} + +pub async fn simple_shell() { + // simple command shell. + let mut buffer = Vec::new(); + let mut new_line = true; + loop { + if new_line { + print!("> "); + new_line = false; + } + if let Some(c) = get_char() { + match c { + CR | LF => { + print!("\n"); + let sign = command(String::from_utf8_lossy(&buffer).as_ref()).await; + if sign { + break; + } + buffer.clear(); + new_line = true; + } + BS | DL => { + if !buffer.is_empty() { + buffer.pop(); + DebugConsole::putchar(BS); + DebugConsole::putchar(SPACE); + DebugConsole::putchar(BS); + } + } + 0..30 => {} + _ => { + buffer.push(c); + DebugConsole::putchar(c); + } + } + } + yield_now().await; + } +} + +pub const USER_WORK_DIR: &str = "/"; + +pub async fn initproc() { + // link files. + // let rootfs = get_filesystem(0).root_dir(); + // let tmpfs = FileItem::fs_open("/home", OpenFlags::O_DIRECTORY).expect("can't open /home"); + // for file in rootfs.read_dir().expect("can't read files") { + // tmpfs + // .link( + // &file.filename, + // rootfs.open(&file.filename, OpenFlags::NONE).unwrap(), + // ) + // .expect("can't link file to tmpfs"); + // } + + println!("start kernel tasks"); + + // command("ls").await; + // command("entry-static.exe crypt").await; + // command("./runtest.exe -w entry-dynamic.exe dlopen").await; + + // let names = include_str!("../../../tools/testcase-step2/run-static.sh"); + // for (i, x) in names + // .split('\n') + // .filter(|x| !x.contains("clocale_mbfuncs") && !x.contains("pthread")) + // .enumerate() + // { + // info!("No.{} started!", i); + // command(x).await; + // info!("No.{} finished!", i); + // } + + // let names = include_str!("../../../tools/testcase-step2/run-static.sh"); + // for (i, x) in names + // .split('\n') + // .filter(|x| x.contains("clocale_mbfuncs") || x.contains("pthread")) + // .enumerate() + // { + // info!("No.{} started!", i); + // command(x).await; + // info!("No.{} finished!", i); + // } + + // let names = include_str!("../../../tools/testcase-step2/run-dynamic.sh"); + // for (i, x) in names + // .split('\n') + // .filter(|x| !x.contains("socket")) + // .enumerate() + // { + // command(x).await; + // info!("No.{} finished!", i); + // } + + // command("./runtest.exe -w entry-static.exe pthread_cancel").await; + // command("./entry-static.exe pthread_cond_smasher").await; + // command("./runtest.exe -w entry-static.exe pthread_cond_smasher").await; + + // command("test-fscanf").await; + // command("./runtest.exe -w entry-static.exe statvfs").await; + // command("entry-static.exe fscanf").await; + // command(" busybox sh").await; + // command("./a.out").await; + + // command("busybox echo run time-test").await; + // command("time-test").await; + + // command("busybox echo run netperf_testcode.sh").await; + // command("busybox sh netperf_testcode.sh").await; + + // command("busybox echo run busybox_testcode.sh").await; + // command("busybox sh busybox_testcode.sh").await; + + // command("busybox echo run libctest_testcode.sh").await; + command("busybox sh libctest_testcode.sh").await; + // command("busybox echo Hello World!").await; + // command("busybox sh").await; + // command("hello").await; + // command("ls").await; + + // simple_shell().await; + // command("busybox sh").await; + + // command("busybox sh ./run-static.sh").await; + // command("./runtest.exe -w entry-dynamic.exe pthread_robust_detach").await; + // command("busybox echo 123").await; + // command("qjs.static test.js").await; + // command("qjs.static").await; + // command("busybox sh").await; + // command("busybox mkdir touch123").await; + // command("busybox rm -r touch123").await; + // command("busybox touch 123 >> touch123/123").await; + // command("busybox cat touch123/123").await; + // command("busybox echo run lua_testcode.sh").await; + // command("busybox sh lua_testcode.sh").await; + + // command("busybox echo run cyclic_testcode.sh").await; + // command("busybox sh cyclictest_testcode.sh").await; + // kill_all_tasks().await; + + // command("libc-bench").await; + + // command("busybox echo run iperf_testcode.sh").await; + // command("busybox sh iperf_testcode.sh").await; + // kill_all_tasks().await; + + // command("busybox echo run iozone_testcode.sh").await; + // command("busybox sh iozone_testcode.sh").await; + + // command("busybox echo run lmbench_testcode.sh").await; + // command("busybox sh lmbench_testcode.sh").await; + + // command("busybox echo run unixbench_testcode.sh").await; + // command("busybox sh unixbench_testcode.sh").await; + + // command("copy-file-range-test-1").await; + // command("copy-file-range-test-2").await; + // command("copy-file-range-test-3").await; + // command("copy-file-range-test-4").await; + // command("interrupts-test-1").await; + // command("interrupts-test-2").await; + + // command("cyclictest -a -i 1000 -t1 -n -p99 -D 1s -q").await; + // command("busybox mkdir test_dir").await; + // command("busybox mv test_dir test").await; + // command("./runtest.exe -w entry-static.exe pthread_cancel_points").await; + // command("./runtest.exe -w entry-static.exe pthread_cancel").await; + // command("./runtest.exe -w entry-static.exe pthread_condattr_setclock").await; + // command("./runtest.exe -w entry-static.exe pthread_cond_smasher").await; + // command("./runtest.exe -w entry-dynamic.exe tls_init").await; + // command("./runtest.exe -w entry-dynamic.exe pthread_cancel_points").await; + // command("./runtest.exe -w entry-static.exe utime").await; + // command("./runtest.exe -w entry-static.exe clocale_mbfuncs").await; + // command("./looper 2 ./multi.sh 1").await; + // command("busybox sh ./multi.sh 1").await; + // command("busybox sh ./tst.sh ./sort.src").await; + // command("entry-dynamic.exe pthread_cancel_points").await; + // command("bin/sh").await; + // command("busybox sh").await; + // command("cloudreve").await; + // command("miniftpd").await; + // command("/server_ftp.out").await; + // command("http_server").await; + // command("ssh-timeouts").await; + // command("sshd").await; + // command("./redis-server /redis.conf --loglevel verbose").await; + // command("redis-cli-static").await; + // command("bin/sh").await; + // command("sshd").await; + // command("busybox sh").await; + // command("/bin/riscv64-linux-musl-gcc main.c").await; + // command("busybox cp /tmp_home/a.out /").await; + // command("busybox sh -c ./a.out").await; + // command("cloudreve").await; + // command("ssh-simple").await; + // command("usr/bin/tcc -run main.c").await; + // command("/bin/bash").await; + // command("bin/bash lmbench_testcode.sh").await; + // command("bin/busybox sh").await; + // command("sqlite_test").await; + // command("lmbench_all lat_syscall -P 1 null").await; + // command("lmbench_all lat_syscall -P 1 read").await; + // command("lmbench_all lat_syscall -P 1 write").await; + // command("./lmbench_all lat_pipe -P 1").await; + // command("bin/bash busybox_testcode.sh").await; + // command("busybox sh lua_testcode.sh").await; + // command("busybox sh lmbench_testcode.sh").await; + // command("bin/busybox sh file_speed.sh").await; + // command("redis-server redis.conf").await; + // command("redis-cli-static").await; + // command("sqlite_test").await; + // command("sqlite_shell").await; + // run_libc_test().await; + // run_all().await; + + // command("helloworld").await; + // command("filelist").await; + // #[cfg(feature = "k210")] + // command("busybox sh").await; + // #[cfg(not(feature = "k210"))] + // command("bin/sh").await; + // simple_shell().await; + // command("busybox").await; + + // switch_to_kernel_page_table(); + println!("!TEST FINISH!"); + + // Shutdown if there just have blankkernel task. + if !TASK_MAP.lock().values().any(|x| { + x.upgrade() + .map(|x| x.get_task_type() != TaskType::BlankKernel) + .unwrap_or(false) + }) { + shutdown(); + } +} diff --git a/kernel/src/tasks/memset.rs b/kernel/src/tasks/memset.rs new file mode 100644 index 00000000..e2007108 --- /dev/null +++ b/kernel/src/tasks/memset.rs @@ -0,0 +1,231 @@ +use alloc::{sync::Arc, vec::Vec}; +use core::{ + cmp::min, + fmt::Debug, + ops::{Deref, DerefMut}, +}; +use devices::PAGE_SIZE; +use frame_allocator::FrameTracker; +use fs::File; +use polyhal::{addr::VirtPage, PageTable}; + +/// Memory set for storing the memory and its map relation. +#[derive(Debug)] +pub struct MemSet(Vec); + +/// Deref for memset, let it iterable +impl Deref for MemSet { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// DerefMut for memset, let it iterable +impl DerefMut for MemSet { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl MemSet { + pub fn new(vec: Vec) -> Self { + Self(vec) + } + + pub fn overlapping(&self, start: usize, end: usize) -> bool { + self.0.iter().any(|x| x.overlapping(start, end)) + } + + pub fn sub_area(&mut self, start: usize, end: usize, pt: &PageTable) { + let mut new_set = Vec::new(); + self.0.retain_mut(|area| { + let res = area.sub(start, end, pt); + if let Some(new_area) = res { + new_set.push(new_area); + } + area.len != 0 + }); + self.0.extend(new_set); + } + + pub fn clear(&mut self) { + self.0.clear(); + } +} + +#[derive(Clone, PartialEq, Debug, Copy)] +pub enum MemType { + CodeSection, + Stack, + Mmap, + Shared, + ShareFile, +} + +#[derive(Clone)] +pub struct MapTrack { + pub vpn: VirtPage, + pub tracker: Arc, + pub rwx: u8, +} + +impl Debug for MapTrack { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!( + "{:#x} -> {:#x}", + self.vpn.to_addr(), + self.tracker.0.to_addr() + )) + } +} + +#[derive(Clone)] +pub struct MemArea { + pub mtype: MemType, + pub mtrackers: Vec, + pub file: Option, + pub offset: usize, + pub start: usize, + pub len: usize, +} + +impl Debug for MemArea { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("MemArea") + .field("mtype", &self.mtype) + .field("mtrackers", &self.mtrackers) + .field("start", &self.start) + .field("len", &self.len) + .finish() + } +} + +impl MemArea { + /// Check the memory is overlapping. + pub fn overlapping(&self, start: usize, end: usize) -> bool { + let self_end = self.start + self.len; + + !((start <= self.start && end <= self.start) || (start >= self_end && end >= self_end)) + } + + /// write page to file + pub fn write_page(&self, mtracker: &MapTrack) { + assert!(self.file.is_some()); + if let Some(file) = &self.file { + let offset = mtracker.vpn.to_addr() + self.offset - self.start; + file.writeat(offset, mtracker.tracker.0.get_buffer()) + .expect("can't write data back to mapped file."); + } + } + + /// Sub the memory from this memory area. + /// the return value indicates whether the memory is splited. + pub fn sub(&mut self, start: usize, end: usize, pt: &PageTable) -> Option { + if !self.overlapping(start, end) { + return None; + } + let range = self.start..self.start + self.len; + let jrange = start..end; + + if range.contains(&start) && range.contains(&end) { + self.len = start - self.start; + let new_area_range = end..range.end; + + if let Some(_file) = &self.file { + self.mtrackers + .iter() + .filter(|x| jrange.contains(&x.vpn.to_addr())) + .for_each(|x| { + self.write_page(x); + }); + }; + // drop the sub memory area pages. + self.mtrackers + .retain(|x| !new_area_range.contains(&x.vpn.to_addr())); + return Some(MemArea { + mtype: self.mtype, + mtrackers: self + .mtrackers + .extract_if(|x| new_area_range.contains(&x.vpn.to_addr())) + .collect(), + file: self.file.clone(), + start: end, + offset: end - self.start, + len: new_area_range.len(), + }); + } + + if jrange.contains(&self.start) && jrange.contains(&range.end) { + self.len = 0; + // TIPS: This area will be remove outside this function. + // So return the None. + if let Some(_file) = &self.file { + self.mtrackers + .iter() + .filter(|x| jrange.contains(&x.vpn.to_addr())) + .for_each(|x| { + self.write_page(x); + }); + }; + self.mtrackers.retain(|x| { + pt.unmap_page(x.vpn); + false + }); + return None; + } + + if range.contains(&start) { + // self.len = cmp::min(start - self.start, self.len); + self.len = start - self.start; + } else if jrange.contains(&self.start) { + self.len = self.start + self.len - end; + self.start = end; + } + if let Some(_file) = &self.file { + self.mtrackers + .iter() + .filter(|x| jrange.contains(&x.vpn.to_addr())) + .for_each(|x| { + self.write_page(x); + }); + }; + // drop the sub memory area pages. + let new_self_rang = self.start..self.start + self.len; + self.mtrackers + .extract_if(|x| !new_self_rang.contains(&x.vpn.to_addr())) + .for_each(|x| { + pt.unmap_page(x.vpn); + }); + None + } + + /// Check the memory area whether contains the specified address. + pub fn contains(&self, addr: usize) -> bool { + self.start <= addr && addr < self.start + self.len + } +} + +impl Drop for MemArea { + fn drop(&mut self) { + if let MemType::ShareFile = &self.mtype { + let start = self.start; + let len = self.len; + let mapfile = self.file.clone().unwrap(); + for tracker in &self.mtrackers { + if Arc::strong_count(&tracker.tracker) > 1 { + continue; + } + + let offset = tracker.vpn.to_addr() - start; + let wlen = min(len - offset, PAGE_SIZE); + + let bytes = &mut tracker.tracker.0.get_buffer()[..wlen]; + mapfile + .writeat(offset, bytes) + .expect("can't write data to file at drop"); + } + } + } +} diff --git a/kernel/src/tasks/mod.rs b/kernel/src/tasks/mod.rs new file mode 100644 index 00000000..cd9f0aa5 --- /dev/null +++ b/kernel/src/tasks/mod.rs @@ -0,0 +1,138 @@ +use alloc::string::String; +use alloc::sync::Weak; +use alloc::{sync::Arc, vec::Vec}; +use devices::get_net_device; +use executor::{current_task, thread, yield_now, AsyncTask, TaskId, DEFAULT_EXECUTOR}; +use hal::{ITimerVal, TimeVal}; +use polyhal::common::get_cpu_num; + +use crate::syscall::{exec_with_process, NET_SERVER}; +use crate::user::entry::user_entry; + +use self::initproc::initproc; + +mod async_ops; +pub mod elf; +mod filetable; +mod initproc; +mod memset; +mod shm; +mod signal; +mod task; + +pub use filetable::FileItem; +pub use memset::{MapTrack, MemArea, MemType}; +pub use shm::{MapedSharedMemory, SharedMemory, SHARED_MEMORY}; +pub use signal::SignalList; +pub use task::UserTask; + +pub use async_ops::{ + futex_requeue, futex_wake, WaitFutex, WaitHandleAbleSignal, WaitPid, WaitSignal, +}; + +pub enum UserTaskControlFlow { + Continue, + Break, +} + +pub fn hexdump(data: &[u8], mut start_addr: usize) { + const PRELAND_WIDTH: usize = 70; + logging::println!("{:-^1$}", " hexdump ", PRELAND_WIDTH); + for offset in (0..data.len()).step_by(16) { + logging::print!("{:08x} ", start_addr); + start_addr += 0x10; + for i in 0..16 { + if offset + i < data.len() { + logging::print!("{:02x} ", data[offset + i]); + } else { + logging::print!("{:02} ", ""); + } + } + + logging::print!("{:>6}", ' '); + + for i in 0..16 { + if offset + i < data.len() { + let c = data[offset + i]; + if (0x20..=0x7e).contains(&c) { + logging::print!("{}", c as char); + } else { + logging::print!("."); + } + } else { + logging::print!("{:02} ", ""); + } + } + + logging::println!(""); + } + logging::println!("{:-^1$}", " hexdump end ", PRELAND_WIDTH); +} + +#[allow(dead_code)] +pub async fn handle_net() { + let mut buffer = vec![0u8; 2048]; + // #[cfg(feature = "net")] + loop { + let res = get_net_device(0).recv(&mut buffer); + if let Ok(rlen) = res { + NET_SERVER.analysis_net_data(&buffer[..rlen]); + } + yield_now().await; + } +} + +pub fn init() { + DEFAULT_EXECUTOR.init(get_cpu_num()); + thread::spawn_blank(initproc()); + #[cfg(feature = "net")] + thread::spawn_blank(KernelTask::new(handle_net())); +} + +pub fn run_tasks() { + DEFAULT_EXECUTOR.run() +} + +pub async fn add_user_task(filename: &str, args: Vec<&str>, envp: Vec<&str>) -> TaskId { + let curr_task = current_task(); + let task = UserTask::new(Weak::new(), initproc::USER_WORK_DIR); + task.before_run(); + exec_with_process( + task.clone(), + String::from(filename), + args.into_iter().map(String::from).collect(), + envp.into_iter().map(String::from).collect(), + ) + .await + .expect("can't add task to excutor"); + curr_task.before_run(); + thread::spawn(task.clone(), user_entry()); + + task.get_task_id() +} + +#[inline] +pub fn current_user_task() -> Arc { + current_task().downcast_arc::().ok().unwrap() +} + +// tms_utime记录的是进程执行用户代码的时间. +// tms_stime记录的是进程执行内核代码的时间. +// tms_cutime记录的是子进程执行用户代码的时间. +// tms_ustime记录的是子进程执行内核代码的时间. +#[allow(dead_code)] +#[derive(Default, Clone, Copy)] +#[allow(clippy::upper_case_acronyms)] +pub struct TMS { + pub utime: u64, + pub stime: u64, + pub cutime: u64, + pub cstime: u64, +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct ProcessTimer { + pub timer: ITimerVal, + pub next: TimeVal, + pub last: TimeVal, +} diff --git a/kernel/src/tasks/shm.rs b/kernel/src/tasks/shm.rs new file mode 100644 index 00000000..1b241b94 --- /dev/null +++ b/kernel/src/tasks/shm.rs @@ -0,0 +1,36 @@ +use alloc::{collections::BTreeMap, sync::Arc, vec::Vec}; +use frame_allocator::FrameTracker; +use sync::Mutex; + +pub struct SharedMemory { + pub trackers: Vec>, + pub deleted: Mutex, +} + +impl SharedMemory { + pub const fn new(trackers: Vec>) -> Self { + Self { + trackers, + deleted: Mutex::new(false), + } + } +} + +#[derive(Clone)] +pub struct MapedSharedMemory { + pub key: usize, + pub mem: Arc, + pub start: usize, + pub size: usize, +} + +impl Drop for MapedSharedMemory { + fn drop(&mut self) { + // self.mem.trackers.remove(self.key); + if Arc::strong_count(&self.mem) == 1 && *self.mem.deleted.lock() { + SHARED_MEMORY.lock().remove(&self.key); + } + } +} + +pub static SHARED_MEMORY: Mutex>> = Mutex::new(BTreeMap::new()); diff --git a/kernel/src/tasks/signal.rs b/kernel/src/tasks/signal.rs new file mode 100644 index 00000000..1ca8f1b6 --- /dev/null +++ b/kernel/src/tasks/signal.rs @@ -0,0 +1,44 @@ +use signal::{SigProcMask, SignalFlags}; + +#[derive(Debug, Clone)] +pub struct SignalList { + pub signal: usize, +} + +impl SignalList { + pub fn new() -> Self { + Self { signal: 0 } + } + + pub fn add_signal(&mut self, signal: SignalFlags) { + self.signal |= signal.bits() as usize; + } + + pub fn has_signal(&self) -> bool { + self.signal != 0 + } + + pub fn try_get_signal(&self) -> Option { + for i in 0..64 { + if self.signal & (1 << i) != 0 { + return Some(SignalFlags::from_bits_truncate(1 << i)); + } + } + None + } + + pub fn remove_signal(&mut self, signal: SignalFlags) { + self.signal &= !signal.bits() as usize; + } + + pub fn has_sig(&self, signal: SignalFlags) -> bool { + // self.signal & !signal.bits() as usize != 0 + self.signal & signal.bits() as usize != 0 + } + + pub fn mask(&self, mask: SigProcMask) -> SignalList { + SignalList { + signal: !mask.mask & self.signal, + } + } +} diff --git a/kernel/src/tasks/task.rs b/kernel/src/tasks/task.rs new file mode 100644 index 00000000..04eaf1b4 --- /dev/null +++ b/kernel/src/tasks/task.rs @@ -0,0 +1,547 @@ +use core::{mem::size_of, ops::Add}; + +use alloc::{ + collections::BTreeMap, + sync::{Arc, Weak}, + vec::Vec, +}; +use devices::PAGE_SIZE; +use executor::{release_task, task::TaskType, task_id_alloc, AsyncTask, TaskId}; +use frame_allocator::{ceil_div, frame_alloc_much}; +use fs::File; +use log::debug; +use polyhal::{ + addr::{PhysPage, VirtAddr, VirtPage}, + trapframe::{TrapFrame, TrapFrameArgs}, + MappingFlags, MappingSize, PageTableWrapper, +}; +use signal::{SigAction, SigProcMask, SignalFlags, REAL_TIME_SIGNAL_NUM}; +use sync::{Mutex, MutexGuard, RwLock}; +use vfscore::OpenFlags; + +use crate::tasks::{ + futex_wake, + memset::{MapTrack, MemArea}, +}; + +use super::{ + filetable::{rlimits_new, FileItem, FileTable}, + memset::{MemSet, MemType}, + shm::MapedSharedMemory, + ProcessTimer, SignalList, TMS, +}; + +pub type FutexTable = BTreeMap>; + +pub struct ProcessControlBlock { + pub memset: MemSet, + pub fd_table: FileTable, + pub curr_dir: Arc, + pub heap: usize, + pub entry: usize, + pub children: Vec>, + pub tms: TMS, + pub rlimits: Vec, + pub sigaction: [SigAction; 65], + pub futex_table: Arc>, + pub shms: Vec, + pub timer: [ProcessTimer; 3], + pub threads: Vec>, + pub exit_code: Option, +} + +pub struct ThreadControlBlock { + pub cx: TrapFrame, + pub sigmask: SigProcMask, + pub clear_child_tid: usize, + pub set_child_tid: usize, + pub signal: SignalList, + pub signal_queue: [usize; REAL_TIME_SIGNAL_NUM], // a queue for real time signals + pub exit_signal: u8, + pub thread_exit_code: Option, +} + +#[allow(dead_code)] +pub struct UserTask { + pub task_id: TaskId, + pub process_id: TaskId, + pub page_table: Arc, + pub pcb: Arc>, + pub parent: RwLock>, + pub tcb: RwLock, +} + +impl UserTask { + pub fn release(&self) { + // Ensure that the task was exited successfully. + assert!(self.exit_code().is_some() || self.tcb.read().thread_exit_code.is_some()); + release_task(self.task_id); + } +} + +impl UserTask { + pub fn new(parent: Weak, work_dir: &str) -> Arc { + let task_id = task_id_alloc(); + // initialize memset + let memset = MemSet::new(vec![]); + + let inner = ProcessControlBlock { + memset, + fd_table: FileTable::new(), + curr_dir: FileItem::fs_open(work_dir, OpenFlags::all()) + .expect("dont' have the home dir"), + heap: 0, + children: Vec::new(), + entry: 0, + tms: Default::default(), + rlimits: rlimits_new(), + sigaction: [SigAction::new(); 65], + futex_table: Arc::new(Mutex::new(BTreeMap::new())), + shms: vec![], + timer: [Default::default(); 3], + exit_code: None, + threads: Vec::new(), + }; + + let tcb = RwLock::new(ThreadControlBlock { + cx: TrapFrame::new(), + sigmask: SigProcMask::new(), + clear_child_tid: 0, + set_child_tid: 0, + signal: SignalList::new(), + signal_queue: [0; REAL_TIME_SIGNAL_NUM], + exit_signal: 0, + thread_exit_code: Option::None, + }); + + let task = Arc::new(Self { + page_table: Arc::new(PageTableWrapper::alloc()), + task_id, + process_id: task_id, + parent: RwLock::new(parent), + pcb: Arc::new(Mutex::new(inner)), + tcb, + }); + task.pcb.lock().threads.push(Arc::downgrade(&task)); + task + } + + pub fn inner_map(&self, mut f: impl FnMut(&mut MutexGuard) -> T) -> T { + f(&mut self.pcb.lock()) + } + + pub fn map(&self, ppn: PhysPage, vpn: VirtPage, flags: MappingFlags) { + // self.page_table.map(ppn, vpn, flags, 3); + self.page_table + .map_page(vpn, ppn, flags, MappingSize::Page4KB); + } + + pub fn frame_alloc(&self, vpn: VirtPage, mtype: MemType, count: usize) -> Option { + self.map_frames(vpn, mtype, count, None, 0, vpn.to_addr(), count * PAGE_SIZE) + } + + #[allow(clippy::too_many_arguments)] + pub fn map_frames( + &self, + vpn: VirtPage, + mtype: MemType, + count: usize, + file: Option, + offset: usize, + start: usize, + len: usize, + ) -> Option { + assert!(count > 0, "can't alloc count = 0 in user_task frame_alloc"); + // alloc trackers and map vpn + let trackers: Vec<_> = frame_alloc_much(count)? + .into_iter() + .enumerate() + .map(|(i, x)| { + let vpn = match vpn.to_addr() == 0 { + true => vpn, + false => vpn.add(i), + }; + MapTrack { + vpn, + tracker: Arc::new(x), + rwx: 0, + } + }) + .collect(); + if vpn.to_addr() != 0 { + debug!( + "map {:#x} @ {:#x} size: {:#x} flags: {:?}", + vpn.to_addr(), + trackers[0].tracker.0.to_addr(), + count * PAGE_SIZE, + MappingFlags::URWX + ); + // map vpn to ppn + trackers + .clone() + .iter() + .filter(|x| x.vpn.to_addr() != 0) + .for_each(|x| self.map(x.tracker.0, x.vpn, MappingFlags::URWX)); + } + let mut inner = self.pcb.lock(); + let ppn = trackers[0].tracker.0; + if mtype == MemType::Stack { + let finded_area = inner.memset.iter_mut().find(|x| x.mtype == mtype); + if let Some(area) = finded_area { + area.mtrackers.extend(trackers); + } else if mtype == MemType::Stack { + inner.memset.push(MemArea { + mtype, + mtrackers: trackers.clone(), + file: None, + offset: 0, + start: 0x7000_0000, + len: 0x1000_0000, + }); + } + } else { + inner.memset.push(MemArea { + mtype, + mtrackers: trackers.clone(), + file, + offset, + start, + len, + }); + } + drop(inner); + + Some(ppn) + } + + // pub fn get_cx_ptr(&self) -> *mut Context { + // // (&mut self.tcb.read().cx) as *mut Context + // unsafe { &mut self.tcb.as_mut_ptr().as_mut().unwrap().cx as _ } + // } + + pub fn force_cx_ref(&self) -> &'static mut TrapFrame { + unsafe { &mut self.tcb.as_mut_ptr().as_mut().unwrap().cx } + } + + pub fn sbrk(&self, incre: isize) -> usize { + let inner = self.pcb.lock(); + let curr_page = inner.heap / PAGE_SIZE; + let after_page = (inner.heap as isize + incre) as usize / PAGE_SIZE; + drop(inner); + // need alloc frame page + if after_page > curr_page { + for i in curr_page..after_page { + self.frame_alloc(VirtPage::new(i + 1), MemType::CodeSection, 1); + } + } + let mut inner = self.pcb.lock(); + inner.heap = (inner.heap as isize + incre) as usize; + inner.heap + } + + pub fn heap(&self) -> usize { + self.pcb.lock().heap + } + + #[inline] + pub fn thread_exit(&self, exit_code: usize) { + let mut tcb_writer = self.tcb.write(); + let uaddr = tcb_writer.clear_child_tid; + if uaddr != 0 { + debug!("write addr: {:#x}", uaddr); + let addr = self + .page_table + .translate(VirtAddr::from(uaddr)) + .expect("can't find a valid addr") + .0; + unsafe { + addr.get_mut_ptr::().write(0); + } + futex_wake(self.pcb.lock().futex_table.clone(), uaddr, 1); + } + tcb_writer.thread_exit_code = Some(exit_code as u32); + let exit_signal = tcb_writer.exit_signal; + drop(tcb_writer); + + // recycle memory resouces if the pcb just used by this thread + if Arc::strong_count(&self.pcb) == 1 { + self.pcb.lock().memset.clear(); + self.pcb.lock().fd_table.clear(); + self.pcb.lock().children.clear(); + self.pcb.lock().exit_code = Some(exit_code); + + if let Some(parent) = self.parent.read().upgrade() { + if exit_signal != 0 { + parent + .tcb + .write() + .signal + .add_signal(SignalFlags::from_usize(exit_signal as usize)); + } else { + parent.tcb.write().signal.add_signal(SignalFlags::SIGCHLD); + } + } + } + + // If this is not the main thread, Just exit immediately, don't store any resources. + if self.task_id != self.process_id { + self.pcb + .lock() + .children + .retain(|x| x.task_id != self.task_id); + self.release(); + } + } + + #[inline] + pub fn exit_with_signal(&self, signal: usize) { + self.exit(128 + signal); + } + + #[inline] + pub fn cow_fork(self: Arc) -> Arc { + // Give the frame_tracker in the memset a type. + // it will contains the frame used for page mapping、 + // mmap or text section. + // and then we can implement COW(copy on write). + let parent_task: Arc = self.clone(); + let work_dir = parent_task + .clone() + .pcb + .lock() + .curr_dir + .path() + .expect("can't get parent work dir in the cow_fork"); + let new_task = Self::new(Arc::downgrade(&parent_task), &work_dir); + let mut new_tcb_writer = new_task.tcb.write(); + // clone fd_table and clone heap + let mut new_pcb = new_task.pcb.lock(); + let mut pcb = self.pcb.lock(); + new_pcb.fd_table.0 = pcb.fd_table.0.clone(); + new_pcb.heap = pcb.heap; + new_tcb_writer.cx = self.tcb.read().cx.clone(); + new_tcb_writer.cx[TrapFrameArgs::RET] = 0; + new_pcb.curr_dir = pcb.curr_dir.clone(); + pcb.children.push(new_task.clone()); + new_pcb.shms = pcb.shms.clone(); + drop(new_pcb); + // cow fork + pcb.memset.iter().for_each(|x| { + let map_area = x.clone(); + map_area.mtrackers.iter().for_each(|x| { + new_task.map(x.tracker.0, x.vpn, MappingFlags::URX); + self.map(x.tracker.0, x.vpn, MappingFlags::URX); + }); + new_task.pcb.lock().memset.push(map_area); + }); + drop(new_tcb_writer); + // copy shm and map them + pcb.shms.iter().for_each(|x| { + x.mem.trackers.iter().enumerate().for_each(|(i, tracker)| { + new_task.map( + tracker.0, + VirtPage::from_addr(x.start).add(i), + MappingFlags::URWX, + ); + }); + }); + new_task + } + + #[inline] + pub fn thread_clone(self: Arc) -> Arc { + // Give the frame_tracker in the memset a type. + // it will contains the frame used for page mapping、 + // mmap or text section. + // and then we can implement COW(copy on write). + let parent_tcb = self.tcb.read(); + + let task_id = task_id_alloc(); + let mut pcb = self.pcb.lock(); + let tcb = RwLock::new(ThreadControlBlock { + cx: parent_tcb.cx.clone(), + sigmask: parent_tcb.sigmask, + clear_child_tid: 0, + set_child_tid: 0, + signal: SignalList::new(), + signal_queue: [0; REAL_TIME_SIGNAL_NUM], + exit_signal: 0, + thread_exit_code: Option::None, + }); + + tcb.write().cx[TrapFrameArgs::RET] = 0; + drop(parent_tcb); + + let new_task = Arc::new(Self { + page_table: self.page_table.clone(), + task_id, + process_id: self.task_id, + parent: RwLock::new(self.parent.read().clone()), + pcb: self.pcb.clone(), + tcb, + }); + pcb.threads.push(Arc::downgrade(&new_task)); + // pcb.children.push(new_task.clone()); + new_task + } + + pub fn push_str(&self, str: &str) -> usize { + self.push_arr(str.as_bytes()) + } + + pub fn push_arr(&self, buffer: &[u8]) -> usize { + let mut tcb = self.tcb.write(); + + const ULEN: usize = size_of::(); + let len = buffer.len(); + let sp = tcb.cx[TrapFrameArgs::SP] - ceil_div(len + 1, ULEN) * ULEN; + + VirtAddr::from(sp) + .slice_mut_with_len(len) + .copy_from_slice(buffer); + tcb.cx[TrapFrameArgs::SP] = sp; + sp + } + + pub fn push_num(&self, num: usize) -> usize { + let mut tcb = self.tcb.write(); + + const ULEN: usize = size_of::(); + let sp = tcb.cx[TrapFrameArgs::SP] - ULEN; + + *VirtAddr::from(sp).get_mut_ref() = num; + tcb.cx[TrapFrameArgs::SP] = sp; + sp + } + + pub fn get_last_free_addr(&self) -> VirtAddr { + let map_last = self + .pcb + .lock() + .memset + .iter() + .filter(|x| x.mtype != MemType::Stack) + .fold(0, |acc, x| { + if acc > x.start + x.len { + acc + } else { + x.start + x.len + } + }); + let shm_last = self.pcb.lock().shms.iter().fold(0, |acc, v| { + if v.start + v.size > acc { + v.start + v.size + } else { + acc + } + }); + + VirtAddr::new(if map_last > shm_last { + map_last + } else { + shm_last + }) + } + + pub fn get_fd(&self, index: usize) -> Option> { + let pcb = self.pcb.lock(); + match index >= pcb.rlimits[7] { + true => None, + false => pcb.fd_table.0[index].clone(), + } + } + + pub fn set_fd(&self, index: usize, value: Arc) { + let mut pcb = self.pcb.lock(); + match index >= pcb.rlimits[7] { + true => {} + false => pcb.fd_table.0[index] = Some(value), + } + } + + pub fn clear_fd(&self, index: usize) { + let mut pcb = self.pcb.lock(); + match index >= pcb.fd_table.len() { + true => {} + false => pcb.fd_table.0[index] = None, + } + } + + pub fn alloc_fd(&self) -> Option { + let mut pcb = self.pcb.lock(); + let index = pcb + .fd_table + .0 + .iter() + .enumerate() + .find(|(i, x)| x.is_none() && *i < pcb.rlimits[7]) + .map(|(i, _)| i); + if index.is_none() && pcb.fd_table.0.len() < pcb.rlimits[7] { + pcb.fd_table.0.push(None); + Some(pcb.fd_table.0.len() - 1) + } else { + index + } + } +} + +impl AsyncTask for UserTask { + fn before_run(&self) { + self.page_table.change(); + } + + fn get_task_id(&self) -> TaskId { + self.task_id + } + + fn get_task_type(&self) -> TaskType { + TaskType::MonolithicTask + } + + #[inline] + fn exit(&self, exit_code: usize) { + let tcb_writer = self.tcb.write(); + let uaddr = tcb_writer.clear_child_tid; + if uaddr != 0 { + debug!("write addr: {:#x}", uaddr); + let addr = self + .page_table + .translate(VirtAddr::from(uaddr)) + .expect("can't find a valid addr") + .0; + unsafe { + addr.get_mut_ptr::().write(0); + } + futex_wake(self.pcb.lock().futex_table.clone(), uaddr, 1); + } + self.pcb.lock().exit_code = Some(exit_code); + let exit_signal = tcb_writer.exit_signal; + drop(tcb_writer); + + // recycle memory resouces if the pcb just used by this thread + if Arc::strong_count(&self.pcb) == 1 { + self.pcb.lock().memset.clear(); + self.pcb.lock().fd_table.clear(); + self.pcb.lock().children.clear(); + } + + if let Some(parent) = self.parent.read().upgrade() { + if exit_signal != 0 { + parent + .tcb + .write() + .signal + .add_signal(SignalFlags::from_usize(exit_signal as usize)); + } else { + parent.tcb.write().signal.add_signal(SignalFlags::SIGCHLD); + } + } else { + self.pcb.lock().children.clear(); + } + } + + #[inline] + fn exit_code(&self) -> Option { + self.pcb.lock().exit_code + } +} diff --git a/kernel/src/user/entry.rs b/kernel/src/user/entry.rs new file mode 100644 index 00000000..29c1c22e --- /dev/null +++ b/kernel/src/user/entry.rs @@ -0,0 +1,127 @@ +use alloc::boxed::Box; +use async_recursion::async_recursion; +use executor::{yield_now, AsyncTask}; +use futures_lite::future; +use hal::TimeVal; +use log::debug; +use polyhal::{boot::boot_page_table, trapframe::TrapFrame}; +use signal::SignalFlags; + +use crate::tasks::{current_user_task, UserTaskControlFlow}; + +use super::UserTaskContainer; + +impl UserTaskContainer { + pub fn check_thread_exit(&self) -> Option { + self.task + .exit_code() + .or(self.task.tcb.read().thread_exit_code.map(|x| x as usize)) + } + + pub fn check_timer(&self) { + let mut pcb = self.task.pcb.lock(); + let timer = &mut pcb.timer[0]; + if timer.next > timer.last { + let now = TimeVal::now(); + if now >= timer.next { + self.task + .tcb + .write() + .signal + .add_signal(SignalFlags::SIGALRM); + timer.last = timer.next; + } + } + } + + pub async fn check_signal(&self) { + loop { + let sig_mask = self.task.tcb.read().sigmask; + let signal = self + .task + .tcb + .read() + .signal + .clone() + .mask(sig_mask) + .try_get_signal(); + if let Some(signal) = signal { + debug!("mask: {:?}", sig_mask); + self.handle_signal(signal.clone()).await; + let mut tcb = self.task.tcb.write(); + tcb.signal.remove_signal(signal.clone()); + // check if it is a real time signal + if let Some(index) = signal.real_time_index() + && tcb.signal_queue[index] > 0 + { + tcb.signal.add_signal(signal.clone()); + tcb.signal_queue[index] -= 1; + } + } else { + break; + } + } + } + + pub async fn entry_point(&mut self, cx_ref: &mut TrapFrame) { + let mut times: i32 = 0; + + loop { + self.check_timer(); + + self.check_signal().await; + + // check for task exit status. + if let Some(exit_code) = self.check_thread_exit() { + debug!( + "program exit with code: {} task_id: {} with inner", + exit_code, + self.task.get_task_id() + ); + break; + } + + let res = future::or(self.handle_syscall(cx_ref), async { + loop { + self.check_signal().await; + + if let Some(_exit_code) = self.check_thread_exit() { + return UserTaskControlFlow::Break; + } + self.check_timer(); + yield_now().await; + } + }); + + if let UserTaskControlFlow::Break = res.await { + break; + } + + if let Some(exit_code) = self.check_thread_exit() { + debug!( + "program exit with code: {} task_id: {} with inner", + exit_code, + self.task.get_task_id() + ); + break; + } + + times += 1; + if times >= 50 { + times = 0; + yield_now().await; + } + } + + debug!("exit_task: {}", self.task.get_task_id()); + boot_page_table().change(); + } +} + +#[async_recursion(Sync)] +pub async fn user_entry() { + let task = current_user_task(); + let cx_ref = task.force_cx_ref(); + let tid = task.get_task_id(); + UserTaskContainer { task, tid }.entry_point(cx_ref).await; +} diff --git a/kernel/src/user/mod.rs b/kernel/src/user/mod.rs new file mode 100644 index 00000000..f0c4caf7 --- /dev/null +++ b/kernel/src/user/mod.rs @@ -0,0 +1,162 @@ +use ::signal::SignalFlags; +use alloc::sync::Arc; +use executor::{AsyncTask, TaskId}; +use frame_allocator::frame_alloc; +use log::{debug, warn}; +use polyhal::addr::VirtPage; +use polyhal::trap::{run_user_task, EscapeReason}; +use polyhal::trapframe::{TrapFrame, TrapFrameArgs}; +use polyhal::{MappingFlags, Time}; + +use crate::tasks::{MapTrack, MemType, UserTask}; +use crate::{ + syscall::consts::SYS_SIGRETURN, + tasks::{hexdump, UserTaskControlFlow}, +}; + +pub mod entry; +pub mod signal; +pub mod socket_pair; + +pub struct UserTaskContainer { + pub task: Arc, + pub tid: TaskId, +} + +/// Copy on write. +/// call this function when trigger store/instruction page fault. +/// copy page or remap page. +pub fn user_cow_int(task: Arc, cx_ref: &mut TrapFrame, addr: usize) { + let vpn = VirtPage::from_addr(addr); + warn!( + "store/instruction page fault @ {:#x} vaddr: {:#x} paddr: {:?} task_id: {}", + cx_ref[TrapFrameArgs::SEPC], + addr, + task.page_table.translate(addr.into()), + task.get_task_id() + ); + let mut pcb = task.pcb.lock(); + let area = pcb.memset.iter_mut().find(|x| x.contains(addr)); + if let Some(area) = area { + let finded = area.mtrackers.iter_mut().find(|x| x.vpn == vpn); + let ppn = match finded { + Some(map_track) => { + if area.mtype == MemType::Shared { + task.tcb.write().signal.add_signal(SignalFlags::SIGSEGV); + return; + } + // tips: this finded will consume a strong count. + debug!("strong count: {}", Arc::strong_count(&map_track.tracker)); + if Arc::strong_count(&map_track.tracker) > 1 { + let src_ppn = map_track.tracker.0; + let dst_ppn = frame_alloc().expect("can't alloc @ user page fault"); + dst_ppn.0.copy_value_from_another(src_ppn); + map_track.tracker = Arc::new(dst_ppn); + } + map_track.tracker.0 + } + None => { + let tracker = Arc::new(frame_alloc().expect("can't alloc frame in cow_fork_int")); + let mtracker = MapTrack { + vpn, + tracker, + rwx: 0b111, + }; + // mtracker.tracker.0.get_buffer().fill(0); + let offset = vpn.to_addr() + area.offset - area.start; + if let Some(file) = &area.file { + file.readat(offset, mtracker.tracker.0.get_buffer()) + .expect("can't read file in cow_fork_int"); + } + let ppn = mtracker.tracker.0; + area.mtrackers.push(mtracker); + ppn + } + }; + + drop(pcb); + task.map(ppn, vpn, MappingFlags::URWX); + } else { + task.tcb.write().signal.add_signal(SignalFlags::SIGSEGV); + } +} + +impl UserTaskContainer { + /// Handle user interrupt. + pub async fn handle_syscall(&self, cx_ref: &mut TrapFrame) -> UserTaskControlFlow { + let ustart = Time::now().raw(); + if matches!(run_user_task(cx_ref), EscapeReason::SysCall) { + self.task + .inner_map(|inner| inner.tms.utime += (Time::now().raw() - ustart) as u64); + + let sstart = Time::now().raw(); + if cx_ref[TrapFrameArgs::SYSCALL] == SYS_SIGRETURN { + return UserTaskControlFlow::Break; + } + + debug!("syscall num: {}", cx_ref[TrapFrameArgs::SYSCALL]); + // sepc += 4, let it can go to next command. + cx_ref.syscall_ok(); + let result = self + .syscall(cx_ref[TrapFrameArgs::SYSCALL], cx_ref.args()) + .await + .map_or_else(|e| -e.code(), |x| x as isize) as usize; + + debug!( + "[task {}] syscall result: {}", + self.task.get_task_id(), + result as isize + ); + + cx_ref[TrapFrameArgs::RET] = result; + self.task + .inner_map(|inner| inner.tms.stime += (Time::now().raw() - sstart) as u64); + } + + // let trap_type = trap_pre_handle(cx_ref); + // match trap_type { + // arch::TrapType::Time => { + // // debug!("time interrupt from user"); + // } + // arch::TrapType::Unknown => { + // debug!("unknown trap: {:#x?}", cx_ref); + // panic!(""); + // } + // arch::TrapType::SupervisorExternal => { + // get_int_device().try_handle_interrupt(u32::MAX); + // } + // } + UserTaskControlFlow::Continue + } +} + +pub fn task_ilegal(task: &Arc, addr: usize, cx_ref: &mut TrapFrame) { + let vpn = VirtPage::from_addr(addr); + let mut pcb = task.pcb.lock(); + let area = pcb.memset.iter_mut().find(|x| x.contains(addr)); + if let Some(area) = area { + let finded = area.mtrackers.iter_mut().find(|x| x.vpn == vpn); + match finded { + Some(_) => { + cx_ref[TrapFrameArgs::SEPC] += 2; + } + None => { + task.tcb.write().signal.add_signal(SignalFlags::SIGILL); + unsafe { + hexdump( + core::slice::from_raw_parts_mut(vpn.to_addr() as _, 0x1000), + vpn.to_addr(), + ); + } + } + }; + } else { + task.tcb.write().signal.add_signal(SignalFlags::SIGILL); + unsafe { + hexdump( + core::slice::from_raw_parts_mut(vpn.to_addr() as _, 0x1000), + vpn.to_addr(), + ); + } + } +} diff --git a/kernel/src/user/signal.rs b/kernel/src/user/signal.rs new file mode 100644 index 00000000..fdc139c4 --- /dev/null +++ b/kernel/src/user/signal.rs @@ -0,0 +1,116 @@ +use core::mem::size_of; + +use executor::AsyncTask; +use log::debug; +use polyhal::trapframe::TrapFrameArgs; +use signal::SignalFlags; + +use crate::syscall::consts::{SignalUserContext, UserRef}; +use crate::tasks::{current_user_task, UserTaskControlFlow}; + +use super::UserTaskContainer; + +impl UserTaskContainer { + pub async fn handle_signal(&self, signal: SignalFlags) { + debug!( + "handle signal: {:?} task_id: {}", + signal, + self.task.get_task_id() + ); + + // if the signal is SIGKILL, then exit the task immediately. + // the SIGKILL can't be catched and be ignored. + if signal == SignalFlags::SIGKILL { + self.task.exit_with_signal(signal.num()); + } + + // get the signal action for the signal. + let sigaction = self.task.pcb.lock().sigaction[signal.num()]; + + // if there doesn't have signal handler. + // Then use default handler. Exit or do nothing. + // SIG_ERR = -1, SIG_DEF(default) = 0, SIG_IGN = 1(ignore) + if sigaction.handler == 0 { + match signal { + SignalFlags::SIGCANCEL | SignalFlags::SIGSEGV | SignalFlags::SIGILL => { + current_user_task().exit_with_signal(signal.num()); + } + _ => {} + } + return; + } + // ignore signal if the handler of is SIG_IGN(1) + if sigaction.handler == 1 { + return; + } + + info!( + "handle signal: {:?} task: {}", + signal, + self.task.get_task_id() + ); + + // let cx_ref = unsafe { task.get_cx_ptr().as_mut().unwrap() }; + let cx_ref = self.task.force_cx_ref(); + // store task_mask and context. + let task_mask = self.task.tcb.read().sigmask; + let store_cx = cx_ref.clone(); + self.task.tcb.write().sigmask = sigaction.mask; + + // alloc space for SignalUserContext at stack and align with 16 bytes. + let sp = (cx_ref[TrapFrameArgs::SP] - 128 - size_of::()) / 16 * 16; + let cx: &mut SignalUserContext = UserRef::::from(sp).get_mut(); + // change task context to do the signal. + let mut tcb = self.task.tcb.write(); + cx.store_ctx(cx_ref); + cx.set_pc(tcb.cx[TrapFrameArgs::SEPC]); + cx.sig_mask = sigaction.mask; + tcb.cx[TrapFrameArgs::SP] = sp; + tcb.cx[TrapFrameArgs::SEPC] = sigaction.handler; + tcb.cx[TrapFrameArgs::RA] = if sigaction.restorer == 0 { + // SIG_RETURN_ADDR + // TODO: add sigreturn addr. + 0 + } else { + sigaction.restorer + }; + tcb.cx[TrapFrameArgs::ARG0] = signal.num(); + tcb.cx[TrapFrameArgs::ARG1] = 0; + tcb.cx[TrapFrameArgs::ARG2] = cx as *mut SignalUserContext as usize; + drop(tcb); + + loop { + if let Some(exit_code) = self.task.exit_code() { + debug!( + "program exit with code: {} task_id: {}", + exit_code, + self.task.get_task_id() + ); + break; + } + + let cx_ref = self.task.force_cx_ref(); + + debug!( + "[task {}]task sepc: {:#x}", + self.task.get_task_id(), + cx_ref[TrapFrameArgs::SEPC] + ); + + if let UserTaskControlFlow::Break = self.handle_syscall(cx_ref).await { + break; + } + } + info!( + "handle signal: {:?} task: {} ended", + signal, + self.task.get_task_id() + ); + // restore sigmask to the mask before doing the signal. + self.task.tcb.write().sigmask = task_mask; + *cx_ref = store_cx; + // copy pc from new_pc + cx_ref[TrapFrameArgs::SEPC] = cx.pc(); + cx.restore_ctx(cx_ref); + } +} diff --git a/kernel/src/user/socket_pair.rs b/kernel/src/user/socket_pair.rs new file mode 100644 index 00000000..d1d5c023 --- /dev/null +++ b/kernel/src/user/socket_pair.rs @@ -0,0 +1,52 @@ +use core::cmp; + +use alloc::{collections::VecDeque, sync::Arc}; +use sync::Mutex; +use vfscore::{INodeInterface, PollEvent, VfsResult}; + +pub struct SocketPair { + inner: Arc>>, +} + +impl INodeInterface for SocketPair { + fn writeat(&self, _offset: usize, buffer: &[u8]) -> VfsResult { + let mut queue = self.inner.lock(); + if queue.len() > 0x50000 { + Err(vfscore::VfsError::Blocking) + } else { + let wlen = buffer.len(); + queue.extend(buffer.iter()); + Ok(wlen) + } + } + + fn readat(&self, _offset: usize, buffer: &mut [u8]) -> VfsResult { + let mut queue = self.inner.lock(); + let rlen = cmp::min(queue.len(), buffer.len()); + queue.drain(..rlen).enumerate().for_each(|(i, x)| { + buffer[i] = x; + }); + if rlen == 0 { + Err(vfscore::VfsError::Blocking) + } else { + Ok(rlen) + } + } + + fn poll(&self, events: PollEvent) -> VfsResult { + let mut res = PollEvent::NONE; + if events.contains(PollEvent::POLLOUT) && self.inner.lock().len() <= 0x50000 { + res |= PollEvent::POLLOUT; + } + if events.contains(PollEvent::POLLIN) && self.inner.lock().len() > 0 { + res |= PollEvent::POLLIN; + } + Ok(res) + } +} + +pub fn create_socket_pair() -> Arc { + Arc::new(SocketPair { + inner: Arc::new(Mutex::new(VecDeque::new())), + }) +} diff --git a/modules/logging/Cargo.toml b/modules/logging/Cargo.toml deleted file mode 100644 index a1f7ef4c..00000000 --- a/modules/logging/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "logging" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log = "0.4.16" -arch = { path = "../../arch" } \ No newline at end of file diff --git a/modules/panic_handler/Cargo.toml b/modules/panic_handler/Cargo.toml deleted file mode 100644 index 48b9d6a9..00000000 --- a/modules/panic_handler/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "panic_handler" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -logging = { path = "../logging" } -arch = { path = "../../arch" } \ No newline at end of file diff --git a/modules/panic_handler/src/lib.rs b/modules/panic_handler/src/lib.rs deleted file mode 100644 index 67503f58..00000000 --- a/modules/panic_handler/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![no_std] -#![feature(panic_info_message)] - -#[macro_use] -extern crate logging; - -use core::panic::PanicInfo; -use arch::shutdown; - -// 程序遇到错误 -#[panic_handler] -fn panic_handler(info: &PanicInfo) -> ! { - println!("\x1b[1;31mpanic: '{}'\x1b[0m", info.message().unwrap()); - println!("!TEST FINISH!"); - shutdown() -} - diff --git a/run.png b/run.png new file mode 100644 index 00000000..67537261 Binary files /dev/null and b/run.png differ diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..f3ea06b4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,12 @@ +[toolchain] +profile = "minimal" +# channel = "nightly-2023-03-29" +channel = "nightly-2023-12-01" +components = ["rust-src", "rustfmt", "clippy", "llvm-tools-preview"] +targets = [ + "riscv64imac-unknown-none-elf", + "riscv64gc-unknown-none-elf", + "x86_64-unknown-none", + "aarch64-unknown-none-softfloat", + "loongarch64-unknown-none" +] diff --git a/scripts/cli-build.ts b/scripts/cli-build.ts new file mode 100644 index 00000000..b34fdd9c --- /dev/null +++ b/scripts/cli-build.ts @@ -0,0 +1,17 @@ +import { Command, CommandOptions } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"; +import { globalArgType } from "./cli-types.ts"; +import { KernelBuilder } from "./kernel.ts"; + + +export const cargoBuild = async function(options: CommandOptions) { + + const builder = new KernelBuilder(options.arch); + await builder.buildElf(); + await builder.convertBin(); + + console.log("options", options); +} + +export const cliCommand = new Command() + .description("Build Rust Kernel") + .action(cargoBuild); diff --git a/scripts/cli-qemu.ts b/scripts/cli-qemu.ts new file mode 100644 index 00000000..b6c4d6f7 --- /dev/null +++ b/scripts/cli-qemu.ts @@ -0,0 +1,83 @@ +import { Command, CommandOptions } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"; +import { globalArgType } from "./cli-types.ts"; +import { KernelBuilder } from "./kernel.ts"; + +class QemuRunner { + arch: string; + bus: string = "device"; + builder: KernelBuilder; + + constructor(options: CommandOptions, builder: KernelBuilder) { + this.arch = options.arch; + this.builder = builder; + if(this.arch == "x86_64" || this.arch == "loongarch64") + this.bus = "pci"; + } + + getQemuArchExec(): string[] { + return { + x86_64: [ + "-machine", + "q35", + "-kernel", + this.builder.elfPath, + "-cpu", + "IvyBridge-v2" + ], + riscv64: [ + "-machine", + "virt", + "-kernel", + this.builder.binPath + ], + aarch64: [ + "-cpu", + "cortex-a72", + "-machine", + "virt", + "-kernel", + this.builder.binPath + ], + loongarch64: [ + "-kernel", + this.builder.elfPath + ] + }[this.arch] ?? []; + } + + async run() { + const qemuCommand = new Deno.Command(`qemu-system-${this.arch}`, { + args: [ + ...this.getQemuArchExec(), + "-m", + "1G", + "-nographic", + "-smp", + "1", + "-D", + "qemu.log", + "-d", + "in_asm,int,pcall,cpu_reset,guest_errors", + + "-drive", + "file=mount.img,if=none,format=raw,id=x0", + "-device", + "virtio-blk-device,drive=x0" + ] + }); + await qemuCommand.spawn().status; + } +} + +async function runQemu(options: CommandOptions) { + const builder = new KernelBuilder(options.arch); + await builder.buildElf(); + await builder.convertBin(); + + const runner = new QemuRunner(options, builder); + await runner.run(); +} + +export const cliCommand = new Command() + .description("Run kernel in the qemu") + .action(runQemu); diff --git a/scripts/cli-types.ts b/scripts/cli-types.ts new file mode 100644 index 00000000..167dacd7 --- /dev/null +++ b/scripts/cli-types.ts @@ -0,0 +1,9 @@ +import { EnumType } from "https://deno.land/x/cliffy@v1.0.0-rc.4/command/mod.ts"; + +export const logLevelEnum = new EnumType(["debug", "info", "warn", "error"]); +export const archEnum = new EnumType(['x86_64', "aarch64", "riscv64", "loongarch64"]); + +export type globalArgType = { + logLevel: typeof logLevelEnum, + arch: typeof archEnum +}; diff --git a/scripts/kernel.ts b/scripts/kernel.ts new file mode 100644 index 00000000..9f695132 --- /dev/null +++ b/scripts/kernel.ts @@ -0,0 +1,72 @@ +const targetMap: Record = { + "riscv64": 'riscv64gc-unknown-none-elf', + "x86_64": 'x86_64-unknown-none', + "aarch64": 'aarch64-unknown-none-softfloat', + "loongarch64": 'loongarch64-unknown-none' +}; + +export class KernelBuilder { + arch: string; + elfPath: string; + binPath: string; + rustflags: string; + + constructor(arch: string) { + this.arch = arch; + this.elfPath = `${Deno.cwd()}/target/${targetMap[arch]}/release/kernel`; + this.binPath = `${this.elfPath}.bin`; + + this.rustflags = Deno.env.get('rustflags') || ""; + } + + buildFlags() { + const rustflags = [ + "-Cforce-frame-pointers=yes", + "-Clink-arg=-no-pie", + "-Ztls-model=local-exec", + `--cfg=root_fs="ext4_rs"`, + '--cfg=board="qemu"' + ]; + + this.rustflags += rustflags.join(" "); + } + + async buildElf() { + this.buildFlags(); + + const buildProc = new Deno.Command("cargo", { + args: [ + "build", + "--release", + "--target", + targetMap[this.arch], + ], + env: { + ROOT_MANIFEST_DIR: Deno.cwd() + "/", + MOUNT_IMG_PATH: "mount.img", + HEAP_SIZE: "0x0180_0000", + BOARD: "qemu", + RUSTFLAGS: this.rustflags + }, + }); + const code = await buildProc.spawn().status; + if(!code.success) { + console.error("Failed to build the kernel"); + Deno.exit(1); + } + } + + async convertBin() { + const objcopyProc = new Deno.Command("rust-objcopy", { + args: [ + `--binary-architecture=${this.arch}`, + this.elfPath, + "--strip-all", + "-O", + "binary", + this.binPath + ] + }); + await objcopyProc.spawn().status; + } +} diff --git a/tftp-burn.sh b/tftp-burn.sh new file mode 100755 index 00000000..aea3aade --- /dev/null +++ b/tftp-burn.sh @@ -0,0 +1,8 @@ +#!/bin/sh +uftpd -n -o ftp=0,tftp=69 . & + +pid=$! + +minicom --color=on -D /dev/ttyUSB0 + +kill -9 $pid diff --git a/tools/iso/boot/grub/grub.cfg b/tools/iso/boot/grub/grub.cfg new file mode 100644 index 00000000..5724d921 --- /dev/null +++ b/tools/iso/boot/grub/grub.cfg @@ -0,0 +1,13 @@ +set timeout=2 +set default=0 # Set the default menu entry + +menuentry "OS Name" { + insmod all_video + # set gfxmode=text + # set gfxpayload=text + # terminal_output console + # The multiboot command replaces the kernel command + # For multiboot v2, use the multiboot2 command + multiboot /example + boot +} diff --git a/tools/opensbi-qemu.bin b/tools/opensbi-qemu.bin new file mode 100644 index 00000000..9fa3494a Binary files /dev/null and b/tools/opensbi-qemu.bin differ diff --git a/tools/qemu_8.2_uefi_bios.bin b/tools/qemu_8.2_uefi_bios.bin new file mode 100644 index 00000000..5b2465c1 Binary files /dev/null and b/tools/qemu_8.2_uefi_bios.bin differ diff --git a/tools/testcase-aarch64/a.out b/tools/testcase-aarch64/a.out new file mode 100755 index 00000000..2c6d86d5 Binary files /dev/null and b/tools/testcase-aarch64/a.out differ diff --git a/tools/testcase-aarch64/arithoh b/tools/testcase-aarch64/arithoh new file mode 100755 index 00000000..31a5a724 Binary files /dev/null and b/tools/testcase-aarch64/arithoh differ diff --git a/tools/testcase-aarch64/bin/true b/tools/testcase-aarch64/bin/true new file mode 100755 index 00000000..139a2ce8 Binary files /dev/null and b/tools/testcase-aarch64/bin/true differ diff --git a/tools/testcase-aarch64/busybox b/tools/testcase-aarch64/busybox new file mode 100755 index 00000000..a5b545ce Binary files /dev/null and b/tools/testcase-aarch64/busybox differ diff --git a/tools/testcase-aarch64/busybox_cmd.txt b/tools/testcase-aarch64/busybox_cmd.txt new file mode 100644 index 00000000..32ebf47c --- /dev/null +++ b/tools/testcase-aarch64/busybox_cmd.txt @@ -0,0 +1,55 @@ +echo "#### independent command test" +ash -c exit +sh -c exit +basename /aaa/bbb +cal +clear +date +df +dirname /aaa/bbb +dmesg +du +expr 1 + 1 +false +true +which ls +uname +uptime +printf "abc\n" +ps +pwd +free +hwclock +kill 10 +ls +sleep 1 +echo "#### file opration test" +touch test.txt +echo "hello world" > test.txt +cat test.txt +cut -c 3 test.txt +od test.txt +head test.txt +tail test.txt +hexdump -C test.txt +md5sum test.txt +echo "ccccccc" >> test.txt +echo "bbbbbbb" >> test.txt +echo "aaaaaaa" >> test.txt +echo "2222222" >> test.txt +echo "1111111" >> test.txt +echo "bbbbbbb" >> test.txt +sort test.txt | ./busybox uniq +stat test.txt +strings test.txt +wc test.txt +[ -f test.txt ] +more test.txt +rm test.txt +mkdir test_dir +mv test_dir test +rmdir test +grep hello busybox_cmd.txt +cp busybox_cmd.txt busybox_cmd.bak +rm busybox_cmd.bak +find -name "busybox_cmd.txt" diff --git a/tools/testcase-aarch64/busybox_testcode.sh b/tools/testcase-aarch64/busybox_testcode.sh new file mode 100755 index 00000000..98d6335b --- /dev/null +++ b/tools/testcase-aarch64/busybox_testcode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST + +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +./busybox cat ./busybox_cmd.txt | while read line +do + eval "./busybox $line" + RTN=$? + if [[ $RTN -ne 0 && $line != "false" ]] ;then + echo "testcase busybox $line fail" + # echo "return: $RTN, cmd: $line" >> $RST + else + echo "testcase busybox $line success" + fi +done + +# echo "TEST END" >> $RST diff --git a/tools/testcase-aarch64/context1 b/tools/testcase-aarch64/context1 new file mode 100755 index 00000000..25e975bd Binary files /dev/null and b/tools/testcase-aarch64/context1 differ diff --git a/tools/testcase-aarch64/copy-file-range-test-1 b/tools/testcase-aarch64/copy-file-range-test-1 new file mode 100755 index 00000000..3ac8b892 Binary files /dev/null and b/tools/testcase-aarch64/copy-file-range-test-1 differ diff --git a/tools/testcase-aarch64/copy-file-range-test-2 b/tools/testcase-aarch64/copy-file-range-test-2 new file mode 100755 index 00000000..c274ef37 Binary files /dev/null and b/tools/testcase-aarch64/copy-file-range-test-2 differ diff --git a/tools/testcase-aarch64/copy-file-range-test-3 b/tools/testcase-aarch64/copy-file-range-test-3 new file mode 100755 index 00000000..f7c880b0 Binary files /dev/null and b/tools/testcase-aarch64/copy-file-range-test-3 differ diff --git a/tools/testcase-aarch64/copy-file-range-test-4 b/tools/testcase-aarch64/copy-file-range-test-4 new file mode 100755 index 00000000..a1188648 Binary files /dev/null and b/tools/testcase-aarch64/copy-file-range-test-4 differ diff --git a/tools/testcase-aarch64/cyclictest b/tools/testcase-aarch64/cyclictest new file mode 100755 index 00000000..c507d01a Binary files /dev/null and b/tools/testcase-aarch64/cyclictest differ diff --git a/tools/testcase-aarch64/cyclictest_testcode.sh b/tools/testcase-aarch64/cyclictest_testcode.sh new file mode 100644 index 00000000..49885ed2 --- /dev/null +++ b/tools/testcase-aarch64/cyclictest_testcode.sh @@ -0,0 +1,33 @@ +run_cyclictest() { + echo "====== cyclictest $1 begin ======" + ./cyclictest $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== cyclictest $1 end: $ans ======" +} + +run_cyclictest NO_STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest NO_STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +echo "====== start hackbench ======" +./hackbench -l 100000000 & +hackbench_pid=$! + +sleep 1 + +run_cyclictest STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +# Kill children in the parent process's interrupt processing, +# so SIGINT is used instead of SIGKILL +kill -2 $hackbench_pid +if [ $? == 0 ]; then + ans="success" +else + ans="fail, ignore STRESS result" +fi +sleep 1 +echo "====== kill hackbench: $ans ======" diff --git a/tools/testcase-aarch64/date.lua b/tools/testcase-aarch64/date.lua new file mode 100644 index 00000000..820ddb9c --- /dev/null +++ b/tools/testcase-aarch64/date.lua @@ -0,0 +1,10 @@ + + +local tbCurrentTime = os.date("*t") + +if tbCurrentTime ~= nil then + return 0 +else + return -1 +end + diff --git a/tools/testcase-aarch64/dhry2 b/tools/testcase-aarch64/dhry2 new file mode 100755 index 00000000..3173df93 Binary files /dev/null and b/tools/testcase-aarch64/dhry2 differ diff --git a/tools/testcase-aarch64/dhry2reg b/tools/testcase-aarch64/dhry2reg new file mode 100755 index 00000000..5c6e466e Binary files /dev/null and b/tools/testcase-aarch64/dhry2reg differ diff --git a/tools/testcase-aarch64/dlopen_dso.so b/tools/testcase-aarch64/dlopen_dso.so new file mode 100755 index 00000000..f3a49dd6 Binary files /dev/null and b/tools/testcase-aarch64/dlopen_dso.so differ diff --git a/tools/testcase-aarch64/double b/tools/testcase-aarch64/double new file mode 100755 index 00000000..f1565d21 Binary files /dev/null and b/tools/testcase-aarch64/double differ diff --git a/tools/testcase-aarch64/entry-dynamic.exe b/tools/testcase-aarch64/entry-dynamic.exe new file mode 100755 index 00000000..ccf302a7 Binary files /dev/null and b/tools/testcase-aarch64/entry-dynamic.exe differ diff --git a/tools/testcase-aarch64/entry-static.exe b/tools/testcase-aarch64/entry-static.exe new file mode 100755 index 00000000..436dca01 Binary files /dev/null and b/tools/testcase-aarch64/entry-static.exe differ diff --git a/tools/testcase-aarch64/execl b/tools/testcase-aarch64/execl new file mode 100755 index 00000000..c988e26f Binary files /dev/null and b/tools/testcase-aarch64/execl differ diff --git a/tools/testcase-aarch64/file_io.lua b/tools/testcase-aarch64/file_io.lua new file mode 100644 index 00000000..86d78155 --- /dev/null +++ b/tools/testcase-aarch64/file_io.lua @@ -0,0 +1,9 @@ +-- Opens a file in write mode +file = io.open("test.txt", "w") + +if file ~= nil then + file:close() + return 0 +else + return -1 +end diff --git a/tools/testcase-aarch64/float b/tools/testcase-aarch64/float new file mode 100755 index 00000000..1ae28dfc Binary files /dev/null and b/tools/testcase-aarch64/float differ diff --git a/tools/testcase-aarch64/fstime b/tools/testcase-aarch64/fstime new file mode 100755 index 00000000..c56332e1 Binary files /dev/null and b/tools/testcase-aarch64/fstime differ diff --git a/tools/testcase-aarch64/hackbench b/tools/testcase-aarch64/hackbench new file mode 100755 index 00000000..9174581d Binary files /dev/null and b/tools/testcase-aarch64/hackbench differ diff --git a/tools/testcase-aarch64/hanoi b/tools/testcase-aarch64/hanoi new file mode 100755 index 00000000..0c796787 Binary files /dev/null and b/tools/testcase-aarch64/hanoi differ diff --git a/tools/testcase-aarch64/hello b/tools/testcase-aarch64/hello new file mode 100755 index 00000000..3dc6ed33 --- /dev/null +++ b/tools/testcase-aarch64/hello @@ -0,0 +1 @@ +/home/xly/oscomp/testsuits-for-oskernel/lmbench/bin/aarch64/lmbench_all hello "$@" diff --git a/tools/testcase-aarch64/int b/tools/testcase-aarch64/int new file mode 100755 index 00000000..38f6d703 Binary files /dev/null and b/tools/testcase-aarch64/int differ diff --git a/tools/testcase-aarch64/interrupts-test-1 b/tools/testcase-aarch64/interrupts-test-1 new file mode 100755 index 00000000..d83c7e85 Binary files /dev/null and b/tools/testcase-aarch64/interrupts-test-1 differ diff --git a/tools/testcase-aarch64/interrupts-test-2 b/tools/testcase-aarch64/interrupts-test-2 new file mode 100755 index 00000000..a9cb6738 Binary files /dev/null and b/tools/testcase-aarch64/interrupts-test-2 differ diff --git a/tools/testcase-aarch64/iozone b/tools/testcase-aarch64/iozone new file mode 100755 index 00000000..06a66f55 Binary files /dev/null and b/tools/testcase-aarch64/iozone differ diff --git a/tools/testcase-aarch64/iozone_testcode.sh b/tools/testcase-aarch64/iozone_testcode.sh new file mode 100644 index 00000000..0c28f97b --- /dev/null +++ b/tools/testcase-aarch64/iozone_testcode.sh @@ -0,0 +1,17 @@ +#!/bin/bash +busybox echo iozone automatic measurements +iozone -a -r 1k -s 4m +busybox echo iozone throughput write/read measurements +iozone -t 4 -i 0 -i 1 -r 1k -s 1m +busybox echo iozone throughput random-read measurements +iozone -t 4 -i 0 -i 2 -r 1k -s 1m +busybox echo iozone throughput read-backwards measurements +iozone -t 4 -i 0 -i 3 -r 1k -s 1m +busybox echo iozone throughput stride-read measurements +iozone -t 4 -i 0 -i 5 -r 1k -s 1m +busybox echo iozone throughput fwrite/fread measurements +iozone -t 4 -i 6 -i 7 -r 1k -s 1m +busybox echo iozone throughput pwrite/pread measurements +iozone -t 4 -i 9 -i 10 -r 1k -s 1m +busybox echo iozone throughtput pwritev/preadv measurements +iozone -t 4 -i 11 -i 12 -r 1k -s 1m diff --git a/tools/testcase-aarch64/iperf3 b/tools/testcase-aarch64/iperf3 new file mode 100755 index 00000000..220ec102 Binary files /dev/null and b/tools/testcase-aarch64/iperf3 differ diff --git a/tools/testcase-aarch64/iperf_testcode.sh b/tools/testcase-aarch64/iperf_testcode.sh new file mode 100644 index 00000000..361c100f --- /dev/null +++ b/tools/testcase-aarch64/iperf_testcode.sh @@ -0,0 +1,35 @@ +host="127.0.0.1" +port="5001" +iperf="./iperf3" + +run_iperf() { + name=$1 + args=$2 + echo "====== iperf $name begin ======" + + $iperf -c $host -p $port -t 2 -i 0 $args + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + + echo "====== iperf $name end: $ans ======" + echo "" +} + + +#start server +$iperf -s -p $port -D + +#basic test +run_iperf "BASIC_UDP" "-u -b 1000G" +run_iperf "BASIC_TCP" "" + +#parallel test +run_iperf "PARALLEL_UDP" "-u -P 5 -b 1000G" +run_iperf "PARALLEL_TCP" "-P 5" + +#reverse test (server sends, client recieves) +run_iperf "REVERSE_UDP" "-u -R -b 1000G" +run_iperf "REVERSE_TCP" "-R" diff --git a/tools/testcase-aarch64/libc-bench b/tools/testcase-aarch64/libc-bench new file mode 100755 index 00000000..7cebae46 Binary files /dev/null and b/tools/testcase-aarch64/libc-bench differ diff --git a/tools/testcase-aarch64/libc.so b/tools/testcase-aarch64/libc.so new file mode 100755 index 00000000..ba7c999f Binary files /dev/null and b/tools/testcase-aarch64/libc.so differ diff --git a/tools/testcase-aarch64/libctest_testcode.sh b/tools/testcase-aarch64/libctest_testcode.sh new file mode 100755 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-aarch64/libctest_testcode.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-aarch64/lmbench_all b/tools/testcase-aarch64/lmbench_all new file mode 100755 index 00000000..a243433a Binary files /dev/null and b/tools/testcase-aarch64/lmbench_all differ diff --git a/tools/testcase-aarch64/lmbench_testcode.sh b/tools/testcase-aarch64/lmbench_testcode.sh new file mode 100644 index 00000000..b4096fff --- /dev/null +++ b/tools/testcase-aarch64/lmbench_testcode.sh @@ -0,0 +1,32 @@ +#!/bin/bash +echo latency measurements +lmbench_all lat_syscall -P 1 null +lmbench_all lat_syscall -P 1 read +lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +lmbench_all lat_select -n 100 -P 1 file +lmbench_all lat_sig -P 1 install +lmbench_all lat_sig -P 1 catch +lmbench_all lat_sig -P 1 prot lat_sig +lmbench_all lat_pipe -P 1 +lmbench_all lat_proc -P 1 fork +lmbench_all lat_proc -P 1 exec +busybox cp hello /tmp +lmbench_all lat_proc -P 1 shell +lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=1m fsync=1 print=3 +lmbench_all lat_pagefault -P 1 /var/tmp/XXX +lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +lmbench_all bw_pipe -P 1 +lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-aarch64/long b/tools/testcase-aarch64/long new file mode 100755 index 00000000..b31a4725 Binary files /dev/null and b/tools/testcase-aarch64/long differ diff --git a/tools/testcase-aarch64/looper b/tools/testcase-aarch64/looper new file mode 100755 index 00000000..5e58428b Binary files /dev/null and b/tools/testcase-aarch64/looper differ diff --git a/tools/testcase-aarch64/lua b/tools/testcase-aarch64/lua new file mode 100755 index 00000000..ef5cd5cb Binary files /dev/null and b/tools/testcase-aarch64/lua differ diff --git a/tools/testcase-aarch64/lua_testcode.sh b/tools/testcase-aarch64/lua_testcode.sh new file mode 100644 index 00000000..3e8ff55b --- /dev/null +++ b/tools/testcase-aarch64/lua_testcode.sh @@ -0,0 +1,9 @@ +./test.sh date.lua +./test.sh file_io.lua +./test.sh max_min.lua +./test.sh random.lua +./test.sh remove.lua +./test.sh round_num.lua +./test.sh sin30.lua +./test.sh sort.lua +./test.sh strings.lua diff --git a/tools/testcase-aarch64/max_min.lua b/tools/testcase-aarch64/max_min.lua new file mode 100644 index 00000000..7381d617 --- /dev/null +++ b/tools/testcase-aarch64/max_min.lua @@ -0,0 +1,9 @@ + + +if math.max(2, 3, 2, 14, 2, 30, -3) == 30 and math.min(2, 3, 2, 14, 2, 30, -3) == -3 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-aarch64/multi.sh b/tools/testcase-aarch64/multi.sh new file mode 100755 index 00000000..2366bda9 --- /dev/null +++ b/tools/testcase-aarch64/multi.sh @@ -0,0 +1,24 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: multi.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)multi.sh:3.4 -- 5/15/91 19:30:24"; +instance=1 + +while [ $instance -le $1 ]; do + "./tst.sh" "./sort.src" & + instance=$(($instance + 1)) +done +wait + diff --git a/tools/testcase-aarch64/netperf b/tools/testcase-aarch64/netperf new file mode 100755 index 00000000..f91be934 Binary files /dev/null and b/tools/testcase-aarch64/netperf differ diff --git a/tools/testcase-aarch64/netperf_testcode.sh b/tools/testcase-aarch64/netperf_testcode.sh new file mode 100644 index 00000000..9a513e10 --- /dev/null +++ b/tools/testcase-aarch64/netperf_testcode.sh @@ -0,0 +1,24 @@ +ip="127.0.0.1" +port=12865 + +run_netperf() { + echo "====== netperf $1 begin ======" + ./netperf -H $ip -p $port -t $1 -l 1 -- $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== netperf $1 end: $ans ======" +} + +./netserver -D -L $ip -p $port & +server_pid=$! + +run_netperf UDP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf TCP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf UDP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_CRR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" + +kill -9 $server_pid diff --git a/tools/testcase-aarch64/netserver b/tools/testcase-aarch64/netserver new file mode 100755 index 00000000..b8de801f Binary files /dev/null and b/tools/testcase-aarch64/netserver differ diff --git a/tools/testcase-aarch64/pipe b/tools/testcase-aarch64/pipe new file mode 100755 index 00000000..ba7247c4 Binary files /dev/null and b/tools/testcase-aarch64/pipe differ diff --git a/tools/testcase-aarch64/random.lua b/tools/testcase-aarch64/random.lua new file mode 100644 index 00000000..f3c27791 --- /dev/null +++ b/tools/testcase-aarch64/random.lua @@ -0,0 +1,13 @@ + + +math.randomseed(os.time()) + +-- num应该大于等于0,小于1 +num = math.random() +if num >= 0 and num < 1 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-aarch64/register b/tools/testcase-aarch64/register new file mode 100755 index 00000000..38f6d703 Binary files /dev/null and b/tools/testcase-aarch64/register differ diff --git a/tools/testcase-aarch64/remove.lua b/tools/testcase-aarch64/remove.lua new file mode 100644 index 00000000..37995ca9 --- /dev/null +++ b/tools/testcase-aarch64/remove.lua @@ -0,0 +1,10 @@ +file = io.open("test.txt", "r") + +if file then + file:close() + if os.remove("test.txt") ~= nil then + return 0 + else + return -1 + end +end diff --git a/tools/testcase-aarch64/round_num.lua b/tools/testcase-aarch64/round_num.lua new file mode 100644 index 00000000..8f60467d --- /dev/null +++ b/tools/testcase-aarch64/round_num.lua @@ -0,0 +1,9 @@ + + +if math.floor(5.6) == 5 and math.ceil(5.6) == 6 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-aarch64/run-dynamic.sh b/tools/testcase-aarch64/run-dynamic.sh new file mode 100755 index 00000000..48a3d36b --- /dev/null +++ b/tools/testcase-aarch64/run-dynamic.sh @@ -0,0 +1,111 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-aarch64/run-static.sh b/tools/testcase-aarch64/run-static.sh new file mode 100755 index 00000000..51eb5710 --- /dev/null +++ b/tools/testcase-aarch64/run-static.sh @@ -0,0 +1,109 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-aarch64/runtest.exe b/tools/testcase-aarch64/runtest.exe new file mode 100755 index 00000000..50c3d973 Binary files /dev/null and b/tools/testcase-aarch64/runtest.exe differ diff --git a/tools/testcase-aarch64/sbin/busybox b/tools/testcase-aarch64/sbin/busybox new file mode 100755 index 00000000..8b5c431c Binary files /dev/null and b/tools/testcase-aarch64/sbin/busybox differ diff --git a/tools/testcase-aarch64/sbin/ls b/tools/testcase-aarch64/sbin/ls new file mode 100755 index 00000000..8b5c431c Binary files /dev/null and b/tools/testcase-aarch64/sbin/ls differ diff --git a/tools/testcase-aarch64/short b/tools/testcase-aarch64/short new file mode 100755 index 00000000..5948dce4 Binary files /dev/null and b/tools/testcase-aarch64/short differ diff --git a/tools/testcase-aarch64/sin30.lua b/tools/testcase-aarch64/sin30.lua new file mode 100644 index 00000000..bcc1e989 --- /dev/null +++ b/tools/testcase-aarch64/sin30.lua @@ -0,0 +1,9 @@ + + +if math.sin(math.rad(30)) == 0.5 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-aarch64/sort.lua b/tools/testcase-aarch64/sort.lua new file mode 100644 index 00000000..942d0395 --- /dev/null +++ b/tools/testcase-aarch64/sort.lua @@ -0,0 +1,13 @@ + + +local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3} + +local rst = {2, 2, 3, 3, 4, 10, 20, 20, 33, 89} + +table.sort(tb) + +if tb == rst then + return 0 +else + return -1 +end diff --git a/tools/testcase-aarch64/spawn b/tools/testcase-aarch64/spawn new file mode 100755 index 00000000..65226333 Binary files /dev/null and b/tools/testcase-aarch64/spawn differ diff --git a/tools/testcase-aarch64/strings.lua b/tools/testcase-aarch64/strings.lua new file mode 100644 index 00000000..2a1b1579 --- /dev/null +++ b/tools/testcase-aarch64/strings.lua @@ -0,0 +1,35 @@ + + +local str = "Jelly Think" + +result = 0 + +-- string.len可以获得字符串的长度 + +if string.len(str) ~= 11 then + result = -1 +end + +-- string.rep返回字符串重复n次的结果 + +str = "ab" + +if string.rep(str, 2) ~= "abab" then + result = -1 +end + +-- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 + +str = "Jelly Think" + +if string.lower(str) ~= "jelly think" then + result = -1 +end + +-- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 + +if string.upper(str) == "JELLY THINK" then + result = -1 +end + +return result diff --git a/tools/testcase-aarch64/syscall b/tools/testcase-aarch64/syscall new file mode 100755 index 00000000..c6e885a9 Binary files /dev/null and b/tools/testcase-aarch64/syscall differ diff --git a/tools/testcase-aarch64/test.sh b/tools/testcase-aarch64/test.sh new file mode 100755 index 00000000..7184e1a7 --- /dev/null +++ b/tools/testcase-aarch64/test.sh @@ -0,0 +1,8 @@ +#!/bin/busybox sh + +./lua $1 +if [ $? == 0 ]; then + echo "testcase lua $1 success" +else + echo "testcase lua $1 fail" +fi diff --git a/tools/testcase-aarch64/test_all.sh b/tools/testcase-aarch64/test_all.sh new file mode 100644 index 00000000..1c4b1cf6 --- /dev/null +++ b/tools/testcase-aarch64/test_all.sh @@ -0,0 +1,22 @@ +busybox echo "run time-test" +./time-test +busybox echo "run busybox_testcode.sh" +./busybox_testcode.sh +busybox echo "run iozone_testcode.sh" +./iozone_testcode.sh +busybox echo "run libctest_testcode.sh" +./libctest_testcode.sh +busybox echo "run libc-bench" +./libc-bench +busybox echo "run lmbench_testcode.sh" +./lmbench_testcode.sh +busybox echo "run lua_testcode.sh" +./lua_testcode.sh +busybox echo "run unixbench_testcode.sh" +./unixbench_testcode.sh +busybox echo "run netperf_testcode.sh" +./netperf_testcode.sh +busybox echo "run iperf_testcode.sh" +./iperf_testcode.sh +busybox echo "run cyclic_testcode.sh" +./cyclic_testcode.sh \ No newline at end of file diff --git a/tools/testcase-aarch64/time-test b/tools/testcase-aarch64/time-test new file mode 100755 index 00000000..13c46c1c Binary files /dev/null and b/tools/testcase-aarch64/time-test differ diff --git a/tools/testcase-aarch64/tls_align_dso.so b/tools/testcase-aarch64/tls_align_dso.so new file mode 100755 index 00000000..68e2423f Binary files /dev/null and b/tools/testcase-aarch64/tls_align_dso.so differ diff --git a/tools/testcase-aarch64/tls_get_new-dtv_dso.so b/tools/testcase-aarch64/tls_get_new-dtv_dso.so new file mode 100755 index 00000000..d70c1336 Binary files /dev/null and b/tools/testcase-aarch64/tls_get_new-dtv_dso.so differ diff --git a/tools/testcase-aarch64/tls_init_dso.so b/tools/testcase-aarch64/tls_init_dso.so new file mode 100755 index 00000000..89bde967 Binary files /dev/null and b/tools/testcase-aarch64/tls_init_dso.so differ diff --git a/tools/testcase-aarch64/tst.sh b/tools/testcase-aarch64/tst.sh new file mode 100755 index 00000000..4b2b025b --- /dev/null +++ b/tools/testcase-aarch64/tst.sh @@ -0,0 +1,20 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: tst.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)tst.sh:3.4 -- 5/15/91 19:30:24"; +./busybox sort > sort.$$ < $1 +./busybox od sort.$$ | ./busybox sort -n -k 1 > od.$$ +./busybox grep the sort.$$ | ./busybox tee grep.$$ | ./busybox wc > wc.$$ +./busybox rm sort.$$ grep.$$ od.$$ wc.$$ diff --git a/tools/testcase-aarch64/unixbench_testcode.sh b/tools/testcase-aarch64/unixbench_testcode.sh new file mode 100755 index 00000000..c127ad94 --- /dev/null +++ b/tools/testcase-aarch64/unixbench_testcode.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +#export CC=gcc + +./dhry2reg 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DHRY2 test(lps): "$0}' +./whetstone-double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+.[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+.[[:digit:]]\+" | ./busybox awk '{print "Unixbench WHETSTONE test(MFLOPS): "$0}' +./syscall 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SYSCALL test(lps): "$0}' +./context1 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox tail -n1 | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench CONTEXT test(lps): "$0}' +./pipe 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench PIPE test(lps): "$0}' +./spawn 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SPAWN test(lps): "$0}' +UB_BINDIR=./ ./execl 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXECL test(lps): "$0}' + +#./fstime +./fstime -w -t 20 -b 256 -m 500 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_SMALL test(KBps): "$0}' +./fstime -r -t 20 -b 256 -m 500 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_SMALL test(KBps): "$0}' +./fstime -c -t 20 -b 256 -m 500 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_SMALL test(KBps): "$0}' + +./fstime -w -t 20 -b 1024 -m 2000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_MIDDLE test(KBps): "$0}' +./fstime -r -t 20 -b 1024 -m 2000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_MIDDLE test(KBps): "$0}' +./fstime -c -t 20 -b 1024 -m 2000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_MIDDLE test(KBps): "$0}' + +./fstime -w -t 20 -b 4096 -m 8000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_BIG test(KBps): "$0}' +./fstime -r -t 20 -b 4096 -m 8000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_BIG test(KBps): "$0}' +./fstime -c -t 20 -b 4096 -m 8000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_BIG test(KBps): "$0}' + + +./looper 20 ./multi.sh 1 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL1 test(lpm): "$0}' +./looper 20 ./multi.sh 8 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL8 test(lpm): "$0}' +./looper 20 ./multi.sh 16 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL16 test(lpm): "$0}' +#./looper 30 dc < ../testdir/dc.dat 2>&1 + +./arithoh 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench ARITHOH test(lps): "$0}' +./short 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHORT test(lps): "$0}' +./int 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench INT test(lps): "$0}' +./long 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench LONG test(lps): "$0}' +./float 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FLOAT test(lps): "$0}' +./double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DOUBLE test(lps): "$0}' +./hanoi 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench HANOI test(lps): "$0}' +./syscall 10 exec | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXEC test(lps): "$0}' diff --git a/tools/testcase-aarch64/whetstone-double b/tools/testcase-aarch64/whetstone-double new file mode 100755 index 00000000..5e763d4a Binary files /dev/null and b/tools/testcase-aarch64/whetstone-double differ diff --git a/tools/testcase-bench/bash_testcode.sh b/tools/testcase-bench/bash_testcode.sh new file mode 100755 index 00000000..46cd4ff0 --- /dev/null +++ b/tools/testcase-bench/bash_testcode.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# 测试创建文件 +echo -n "Bash Test TOUCH FILE " > log +touch exists.file +if [ -f "exists.file" ] +then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log + +# 测试读取文件 +echo -n "Bash Test READ FILE " > log +echo "Hello" >> 1.txt +var=$(cat 1.txt) +if [ $var = "Hello" ]; then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log + +# 测试循环 +echo -n "Bash Test LOOP " > log +sum=0 +for i in `seq 1 100` +do + sum=$(($sum + $i)) +done +if [ $sum = 5050 ]; then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log + +# 测试删除文件 +echo -n "Bash Test DELETE FILE " > log +rm exists.file +if [ -f "exists.file" ] +then + echo "FAILED" >> log +else + echo "PASS" >> log +fi +cat log +rm log + +# 测试执行命令 +echo -n "Bash Test DELETE EVAL COMMAND " > log +eval "touch exists.file" +if [ -f "exists.file" ] +then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log + + +# 测试执行运算 +echo -n "Bash Test EXPR" > log +num=`expr 1 + 1` +if [ $num = 2 ] +then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log + + +# 测试管道 +echo -n "Bash Test PIPE" > log +str=$(echo "hello" | cut -c 3-) +if [ $str = 'llo' ] +then + echo "PASS" >> log +else + echo "FAILED" >> log +fi +cat log +rm log \ No newline at end of file diff --git a/tools/testcase-bench/bin/bash b/tools/testcase-bench/bin/bash new file mode 100755 index 00000000..510ad4f7 Binary files /dev/null and b/tools/testcase-bench/bin/bash differ diff --git a/tools/testcase-bench/bin/busybox b/tools/testcase-bench/bin/busybox new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/busybox differ diff --git a/tools/testcase-bench/bin/cat b/tools/testcase-bench/bin/cat new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/cat differ diff --git a/tools/testcase-bench/bin/clear b/tools/testcase-bench/bin/clear new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/clear differ diff --git a/tools/testcase-bench/bin/cp b/tools/testcase-bench/bin/cp new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/cp differ diff --git a/tools/testcase-bench/bin/cut b/tools/testcase-bench/bin/cut new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/cut differ diff --git a/tools/testcase-bench/bin/expr b/tools/testcase-bench/bin/expr new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/expr differ diff --git a/tools/testcase-bench/bin/grep b/tools/testcase-bench/bin/grep new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/grep differ diff --git a/tools/testcase-bench/bin/ls b/tools/testcase-bench/bin/ls new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/ls differ diff --git a/tools/testcase-bench/bin/rm b/tools/testcase-bench/bin/rm new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/rm differ diff --git a/tools/testcase-bench/bin/seq b/tools/testcase-bench/bin/seq new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/seq differ diff --git a/tools/testcase-bench/bin/sh b/tools/testcase-bench/bin/sh new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/sh differ diff --git a/tools/testcase-bench/bin/touch b/tools/testcase-bench/bin/touch new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/touch differ diff --git a/tools/testcase-bench/bin/vi b/tools/testcase-bench/bin/vi new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-bench/bin/vi differ diff --git a/tools/testcase-bench/busybox_testcode.sh b/tools/testcase-bench/busybox_testcode.sh new file mode 100755 index 00000000..c40f2940 --- /dev/null +++ b/tools/testcase-bench/busybox_testcode.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST +# +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +cat ./busybox_cmd.txt | while read line +do + eval "busybox $line" >> run.txt + RTN=$? + if [[ $RTN == 0 || $line == "false" ]] ;then + echo "testcase busybox $line success" + echo "$line" >> passed.txt + fi +done + +cat run.txt + +cat passed.txt + +# echo "TEST END" >> $RST diff --git a/tools/testcase-bench/cloudreve b/tools/testcase-bench/cloudreve new file mode 100755 index 00000000..7e5bc977 Binary files /dev/null and b/tools/testcase-bench/cloudreve differ diff --git a/tools/testcase-bench/cloudreve.db b/tools/testcase-bench/cloudreve.db new file mode 100644 index 00000000..082a884e Binary files /dev/null and b/tools/testcase-bench/cloudreve.db differ diff --git a/tools/testcase-bench/conf.ini b/tools/testcase-bench/conf.ini new file mode 100644 index 00000000..1946aca5 --- /dev/null +++ b/tools/testcase-bench/conf.ini @@ -0,0 +1,6 @@ +[System] +Debug = false +Mode = master +Listen = :5212 +SessionSecret = 09VW7bqOnPDW4nOd3p8BUxZNUX86sKhgy4daq2IGFi31p2vVxKNMLQZfnwxZRKLt +HashIDSalt = 9KBuCHQw8nD28LeXyS3TjxB1yo5qeOYjA8hpKtpsg4BabyxWjKbxR3MfvNSaMSLF diff --git a/tools/testcase-bench/etc/passwd b/tools/testcase-bench/etc/passwd new file mode 100644 index 00000000..0cabc85a --- /dev/null +++ b/tools/testcase-bench/etc/passwd @@ -0,0 +1 @@ +root:x:0:0::/root:/bin/bash \ No newline at end of file diff --git a/tools/testcase-bench/file.sqlite b/tools/testcase-bench/file.sqlite new file mode 100644 index 00000000..01d651d8 Binary files /dev/null and b/tools/testcase-bench/file.sqlite differ diff --git a/tools/testcase-bench/file_speed.sh b/tools/testcase-bench/file_speed.sh new file mode 100644 index 00000000..82ff974c --- /dev/null +++ b/tools/testcase-bench/file_speed.sh @@ -0,0 +1,4 @@ +echo "File Speed TEST" +# busybox touch /var/tmp/hello +# ./lmbench_all lat_proc -P 1 shell +./lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=2m fsync=1 print=3 diff --git a/tools/testcase-bench/hello_server b/tools/testcase-bench/hello_server new file mode 100755 index 00000000..f3342315 Binary files /dev/null and b/tools/testcase-bench/hello_server differ diff --git a/tools/testcase-bench/index.html b/tools/testcase-bench/index.html new file mode 100644 index 00000000..c87ef5aa --- /dev/null +++ b/tools/testcase-bench/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + +
+

lose-net-stack

+

lose-net-stack 是一个使用 rust 编写的网络协议栈。

+
+ +
+
+
+

Rust

+

Rust

+

Rust是一门系统编程语言,专注于安全,尤其是并发安全,支持函数式和命令式以及泛型等编程范式的多范式语言

+
+
+

网络协议栈

+

net stack

+

协议栈,又称协议堆叠,是计算机网络协议套件的一个具体的软件实现。协议套件中的一个协议通常是只为一个目的而设计的,这样可以使得设计更容易。

+
+
+

仓库地址

+

repo url

+

https://github.com/yfblock/lose-net-stack

+
+
+
+ + + \ No newline at end of file diff --git a/tools/testcase-bench/libc.so b/tools/testcase-bench/libc.so new file mode 100755 index 00000000..f415ed9d Binary files /dev/null and b/tools/testcase-bench/libc.so differ diff --git a/tools/testcase-bench/lmbench_all b/tools/testcase-bench/lmbench_all new file mode 100755 index 00000000..bae468a9 Binary files /dev/null and b/tools/testcase-bench/lmbench_all differ diff --git a/tools/testcase-bench/lmbench_testcode.sh b/tools/testcase-bench/lmbench_testcode.sh new file mode 100755 index 00000000..dee4f66a --- /dev/null +++ b/tools/testcase-bench/lmbench_testcode.sh @@ -0,0 +1,35 @@ +#!/bin/bash +echo latency measurements +./lmbench_all lat_syscall -P 1 null +./lmbench_all lat_syscall -P 1 read +./lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +./lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +./lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +./lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +./lmbench_all lat_select -n 100 -P 1 file +./lmbench_all lat_sig -P 1 install +./lmbench_all lat_sig -P 1 catch +./lmbench_all lat_sig -P 1 prot lat_sig +./lmbench_all lat_pipe -P 1 +./lmbench_all lat_proc -P 1 fork +./lmbench_all lat_proc -P 1 exec +busybox touch /var/tmp/hello +./lmbench_all lat_proc -P 1 shell +./lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=2m fsync=1 print=3 +# unsupport temporarily +# ./lmbench_all lat_pagefault -P 1 /var/tmp/XXX +./lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +./lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +# unsupport temporarily +# ./lmbench_all bw_pipe -P 1 +./lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +./lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +./lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +./lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +# unsupport temporarily +# ./lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-bench/main.c b/tools/testcase-bench/main.c new file mode 100644 index 00000000..498a3834 --- /dev/null +++ b/tools/testcase-bench/main.c @@ -0,0 +1,9 @@ +#include + +int main() { + return 0; +} + +void __libc_start_main() { + return; +} \ No newline at end of file diff --git a/tools/testcase-bench/nbench b/tools/testcase-bench/nbench new file mode 100755 index 00000000..074eec7f Binary files /dev/null and b/tools/testcase-bench/nbench differ diff --git a/tools/testcase-bench/redis-cli-static b/tools/testcase-bench/redis-cli-static new file mode 100644 index 00000000..21b3d8c4 Binary files /dev/null and b/tools/testcase-bench/redis-cli-static differ diff --git a/tools/testcase-bench/redis-server b/tools/testcase-bench/redis-server new file mode 100644 index 00000000..fb38b288 Binary files /dev/null and b/tools/testcase-bench/redis-server differ diff --git a/tools/testcase-bench/redis.conf b/tools/testcase-bench/redis.conf new file mode 100644 index 00000000..c5458f0b --- /dev/null +++ b/tools/testcase-bench/redis.conf @@ -0,0 +1,2 @@ +protected-mode no +port 6379 diff --git a/tools/testcase-bench/redis.sh b/tools/testcase-bench/redis.sh new file mode 100644 index 00000000..99ed41fc --- /dev/null +++ b/tools/testcase-bench/redis.sh @@ -0,0 +1,2 @@ +./redis-server /redis.conf --loglevel verbose & +./redis-cli-static \ No newline at end of file diff --git a/tools/testcase-bench/runtest.exe b/tools/testcase-bench/runtest.exe new file mode 100755 index 00000000..4535f4bf Binary files /dev/null and b/tools/testcase-bench/runtest.exe differ diff --git a/tools/testcase-bench/sqlite_shell b/tools/testcase-bench/sqlite_shell new file mode 100755 index 00000000..9baf4196 Binary files /dev/null and b/tools/testcase-bench/sqlite_shell differ diff --git a/tools/testcase-bench/sqlite_test b/tools/testcase-bench/sqlite_test new file mode 100755 index 00000000..149f7c12 Binary files /dev/null and b/tools/testcase-bench/sqlite_test differ diff --git a/tools/testcase-bench/ssh-simple b/tools/testcase-bench/ssh-simple new file mode 100755 index 00000000..6d6b9beb Binary files /dev/null and b/tools/testcase-bench/ssh-simple differ diff --git a/tools/testcase-bench/sshd b/tools/testcase-bench/sshd new file mode 100755 index 00000000..5ea43319 Binary files /dev/null and b/tools/testcase-bench/sshd differ diff --git a/tools/testcase-gcc/.gitignore b/tools/testcase-gcc/.gitignore new file mode 100644 index 00000000..9c06b5f9 --- /dev/null +++ b/tools/testcase-gcc/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!main.c \ No newline at end of file diff --git a/tools/testcase-gcc/main.c b/tools/testcase-gcc/main.c new file mode 100644 index 00000000..8a0eae61 --- /dev/null +++ b/tools/testcase-gcc/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("hello world\n"); + return 0; +} \ No newline at end of file diff --git a/tools/testcase-loongarch64/bin/sleep b/tools/testcase-loongarch64/bin/sleep new file mode 100755 index 00000000..29cef922 Binary files /dev/null and b/tools/testcase-loongarch64/bin/sleep differ diff --git a/tools/testcase-loongarch64/bin/true b/tools/testcase-loongarch64/bin/true new file mode 100755 index 00000000..29cef922 Binary files /dev/null and b/tools/testcase-loongarch64/bin/true differ diff --git a/tools/testcase-loongarch64/blank b/tools/testcase-loongarch64/blank new file mode 100644 index 00000000..e69de29b diff --git a/tools/testcase-loongarch64/busybox b/tools/testcase-loongarch64/busybox new file mode 100755 index 00000000..3cae315d Binary files /dev/null and b/tools/testcase-loongarch64/busybox differ diff --git a/tools/testcase-loongarch64/busybox_cmd.txt b/tools/testcase-loongarch64/busybox_cmd.txt new file mode 100644 index 00000000..563a40bf --- /dev/null +++ b/tools/testcase-loongarch64/busybox_cmd.txt @@ -0,0 +1,55 @@ +echo "#### independent command test" +ash -c exit +sh -c exit +basename /aaa/bbb +cal +clear +date +df +dirname /aaa/bbb +dmesg +du +expr 1 + 1 +false +true +which busybox +uname +uptime +printf "abc\n" +ps +pwd +free +hwclock +kill 4 +ls +sleep 1 +echo "#### file opration test" +touch test.txt +echo "hello world" > test.txt +cat test.txt +cut -c 3 test.txt +od test.txt +head test.txt +tail test.txt +hexdump -C test.txt +md5sum test.txt +echo "ccccccc" >> test.txt +echo "bbbbbbb" >> test.txt +echo "aaaaaaa" >> test.txt +echo "2222222" >> test.txt +echo "1111111" >> test.txt +echo "bbbbbbb" >> test.txt +sort test.txt | ./busybox uniq +stat test.txt +strings test.txt +wc test.txt +[ -f test.txt ] +more test.txt +rm test.txt +mkdir test_dir +mv test_dir test +rmdir test +grep hello busybox_cmd.txt +cp busybox_cmd.txt busybox_cmd.bak +rm busybox_cmd.bak +find -name "busybox_cmd.txt" diff --git a/tools/testcase-loongarch64/busybox_testcode.sh b/tools/testcase-loongarch64/busybox_testcode.sh new file mode 100755 index 00000000..98d6335b --- /dev/null +++ b/tools/testcase-loongarch64/busybox_testcode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST + +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +./busybox cat ./busybox_cmd.txt | while read line +do + eval "./busybox $line" + RTN=$? + if [[ $RTN -ne 0 && $line != "false" ]] ;then + echo "testcase busybox $line fail" + # echo "return: $RTN, cmd: $line" >> $RST + else + echo "testcase busybox $line success" + fi +done + +# echo "TEST END" >> $RST diff --git a/tools/testcase-loongarch64/copy-file-range-test-1 b/tools/testcase-loongarch64/copy-file-range-test-1 new file mode 100755 index 00000000..a86b5a2e Binary files /dev/null and b/tools/testcase-loongarch64/copy-file-range-test-1 differ diff --git a/tools/testcase-loongarch64/copy-file-range-test-2 b/tools/testcase-loongarch64/copy-file-range-test-2 new file mode 100755 index 00000000..77422e8b Binary files /dev/null and b/tools/testcase-loongarch64/copy-file-range-test-2 differ diff --git a/tools/testcase-loongarch64/copy-file-range-test-3 b/tools/testcase-loongarch64/copy-file-range-test-3 new file mode 100755 index 00000000..8d19d50c Binary files /dev/null and b/tools/testcase-loongarch64/copy-file-range-test-3 differ diff --git a/tools/testcase-loongarch64/copy-file-range-test-4 b/tools/testcase-loongarch64/copy-file-range-test-4 new file mode 100755 index 00000000..033d3955 Binary files /dev/null and b/tools/testcase-loongarch64/copy-file-range-test-4 differ diff --git a/tools/testcase-loongarch64/cyclictest b/tools/testcase-loongarch64/cyclictest new file mode 100755 index 00000000..8c653197 Binary files /dev/null and b/tools/testcase-loongarch64/cyclictest differ diff --git a/tools/testcase-loongarch64/cyclictest_testcode.sh b/tools/testcase-loongarch64/cyclictest_testcode.sh new file mode 100644 index 00000000..42addc11 --- /dev/null +++ b/tools/testcase-loongarch64/cyclictest_testcode.sh @@ -0,0 +1,34 @@ +run_cyclictest() { + echo "====== cyclictest $1 begin ======" + ./cyclictest $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== cyclictest $1 end: $ans ======" +} + +run_cyclictest NO_STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest NO_STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +echo "====== start hackbench ======" +# Change 100000000 to 10000, because loongarch64 simulator is too slow. +./hackbench -l 1000 & +hackbench_pid=$! + +sleep 1 + +run_cyclictest STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +# Kill children in the parent process's interrupt processing, +# so SIGINT is used instead of SIGKILL +kill -2 $hackbench_pid +if [ $? == 0 ]; then + ans="success" +else + ans="fail, ignore STRESS result" +fi +sleep 1 +echo "====== kill hackbench: $ans ======" diff --git a/tools/testcase-loongarch64/date.lua b/tools/testcase-loongarch64/date.lua new file mode 100644 index 00000000..820ddb9c --- /dev/null +++ b/tools/testcase-loongarch64/date.lua @@ -0,0 +1,10 @@ + + +local tbCurrentTime = os.date("*t") + +if tbCurrentTime ~= nil then + return 0 +else + return -1 +end + diff --git a/tools/testcase-loongarch64/dlopen_dso.so b/tools/testcase-loongarch64/dlopen_dso.so new file mode 100755 index 00000000..56a65657 Binary files /dev/null and b/tools/testcase-loongarch64/dlopen_dso.so differ diff --git a/tools/testcase-loongarch64/entry-dynamic.exe b/tools/testcase-loongarch64/entry-dynamic.exe new file mode 100755 index 00000000..ff8b9183 Binary files /dev/null and b/tools/testcase-loongarch64/entry-dynamic.exe differ diff --git a/tools/testcase-loongarch64/entry-static.exe b/tools/testcase-loongarch64/entry-static.exe new file mode 100755 index 00000000..64d9f40e Binary files /dev/null and b/tools/testcase-loongarch64/entry-static.exe differ diff --git a/tools/testcase-loongarch64/file_io.lua b/tools/testcase-loongarch64/file_io.lua new file mode 100644 index 00000000..86d78155 --- /dev/null +++ b/tools/testcase-loongarch64/file_io.lua @@ -0,0 +1,9 @@ +-- Opens a file in write mode +file = io.open("test.txt", "w") + +if file ~= nil then + file:close() + return 0 +else + return -1 +end diff --git a/tools/testcase-loongarch64/hackbench b/tools/testcase-loongarch64/hackbench new file mode 100755 index 00000000..4e84abf7 Binary files /dev/null and b/tools/testcase-loongarch64/hackbench differ diff --git a/tools/testcase-loongarch64/hello b/tools/testcase-loongarch64/hello new file mode 100755 index 00000000..eec70b4c --- /dev/null +++ b/tools/testcase-loongarch64/hello @@ -0,0 +1 @@ +/home/yufeng/Downloads/oscomp-testsuits-loongarch/lmbench/bin/loongarch64/lmbench_all hello "$@" diff --git a/tools/testcase-loongarch64/interrupts-test-1 b/tools/testcase-loongarch64/interrupts-test-1 new file mode 100755 index 00000000..5a6e6c4a Binary files /dev/null and b/tools/testcase-loongarch64/interrupts-test-1 differ diff --git a/tools/testcase-loongarch64/interrupts-test-2 b/tools/testcase-loongarch64/interrupts-test-2 new file mode 100755 index 00000000..ffe159cd Binary files /dev/null and b/tools/testcase-loongarch64/interrupts-test-2 differ diff --git a/tools/testcase-loongarch64/iperf3 b/tools/testcase-loongarch64/iperf3 new file mode 100755 index 00000000..6ccbe8e2 Binary files /dev/null and b/tools/testcase-loongarch64/iperf3 differ diff --git a/tools/testcase-loongarch64/iperf_testcode.sh b/tools/testcase-loongarch64/iperf_testcode.sh new file mode 100644 index 00000000..361c100f --- /dev/null +++ b/tools/testcase-loongarch64/iperf_testcode.sh @@ -0,0 +1,35 @@ +host="127.0.0.1" +port="5001" +iperf="./iperf3" + +run_iperf() { + name=$1 + args=$2 + echo "====== iperf $name begin ======" + + $iperf -c $host -p $port -t 2 -i 0 $args + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + + echo "====== iperf $name end: $ans ======" + echo "" +} + + +#start server +$iperf -s -p $port -D + +#basic test +run_iperf "BASIC_UDP" "-u -b 1000G" +run_iperf "BASIC_TCP" "" + +#parallel test +run_iperf "PARALLEL_UDP" "-u -P 5 -b 1000G" +run_iperf "PARALLEL_TCP" "-P 5" + +#reverse test (server sends, client recieves) +run_iperf "REVERSE_UDP" "-u -R -b 1000G" +run_iperf "REVERSE_TCP" "-R" diff --git a/tools/testcase-loongarch64/libc-bench b/tools/testcase-loongarch64/libc-bench new file mode 100755 index 00000000..e0e67bab Binary files /dev/null and b/tools/testcase-loongarch64/libc-bench differ diff --git a/tools/testcase-loongarch64/libc.so b/tools/testcase-loongarch64/libc.so new file mode 100755 index 00000000..e0590756 Binary files /dev/null and b/tools/testcase-loongarch64/libc.so differ diff --git a/tools/testcase-loongarch64/libctest_testcode.sh b/tools/testcase-loongarch64/libctest_testcode.sh new file mode 100644 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-loongarch64/libctest_testcode.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-loongarch64/lmbench_all b/tools/testcase-loongarch64/lmbench_all new file mode 100755 index 00000000..8a9404b2 Binary files /dev/null and b/tools/testcase-loongarch64/lmbench_all differ diff --git a/tools/testcase-loongarch64/lmbench_testcode.sh b/tools/testcase-loongarch64/lmbench_testcode.sh new file mode 100644 index 00000000..b4096fff --- /dev/null +++ b/tools/testcase-loongarch64/lmbench_testcode.sh @@ -0,0 +1,32 @@ +#!/bin/bash +echo latency measurements +lmbench_all lat_syscall -P 1 null +lmbench_all lat_syscall -P 1 read +lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +lmbench_all lat_select -n 100 -P 1 file +lmbench_all lat_sig -P 1 install +lmbench_all lat_sig -P 1 catch +lmbench_all lat_sig -P 1 prot lat_sig +lmbench_all lat_pipe -P 1 +lmbench_all lat_proc -P 1 fork +lmbench_all lat_proc -P 1 exec +busybox cp hello /tmp +lmbench_all lat_proc -P 1 shell +lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=1m fsync=1 print=3 +lmbench_all lat_pagefault -P 1 /var/tmp/XXX +lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +lmbench_all bw_pipe -P 1 +lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-loongarch64/lua b/tools/testcase-loongarch64/lua new file mode 100755 index 00000000..10fd6e7b Binary files /dev/null and b/tools/testcase-loongarch64/lua differ diff --git a/tools/testcase-loongarch64/lua_testcode.sh b/tools/testcase-loongarch64/lua_testcode.sh new file mode 100644 index 00000000..3e8ff55b --- /dev/null +++ b/tools/testcase-loongarch64/lua_testcode.sh @@ -0,0 +1,9 @@ +./test.sh date.lua +./test.sh file_io.lua +./test.sh max_min.lua +./test.sh random.lua +./test.sh remove.lua +./test.sh round_num.lua +./test.sh sin30.lua +./test.sh sort.lua +./test.sh strings.lua diff --git a/tools/testcase-loongarch64/main b/tools/testcase-loongarch64/main new file mode 100755 index 00000000..86427012 Binary files /dev/null and b/tools/testcase-loongarch64/main differ diff --git a/tools/testcase-loongarch64/max_min.lua b/tools/testcase-loongarch64/max_min.lua new file mode 100644 index 00000000..7381d617 --- /dev/null +++ b/tools/testcase-loongarch64/max_min.lua @@ -0,0 +1,9 @@ + + +if math.max(2, 3, 2, 14, 2, 30, -3) == 30 and math.min(2, 3, 2, 14, 2, 30, -3) == -3 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-loongarch64/netperf b/tools/testcase-loongarch64/netperf new file mode 100755 index 00000000..2970d7f9 Binary files /dev/null and b/tools/testcase-loongarch64/netperf differ diff --git a/tools/testcase-loongarch64/netperf_testcode.sh b/tools/testcase-loongarch64/netperf_testcode.sh new file mode 100644 index 00000000..9a513e10 --- /dev/null +++ b/tools/testcase-loongarch64/netperf_testcode.sh @@ -0,0 +1,24 @@ +ip="127.0.0.1" +port=12865 + +run_netperf() { + echo "====== netperf $1 begin ======" + ./netperf -H $ip -p $port -t $1 -l 1 -- $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== netperf $1 end: $ans ======" +} + +./netserver -D -L $ip -p $port & +server_pid=$! + +run_netperf UDP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf TCP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf UDP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_CRR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" + +kill -9 $server_pid diff --git a/tools/testcase-loongarch64/netserver b/tools/testcase-loongarch64/netserver new file mode 100755 index 00000000..afc3ae28 Binary files /dev/null and b/tools/testcase-loongarch64/netserver differ diff --git a/tools/testcase-loongarch64/random.lua b/tools/testcase-loongarch64/random.lua new file mode 100644 index 00000000..f3c27791 --- /dev/null +++ b/tools/testcase-loongarch64/random.lua @@ -0,0 +1,13 @@ + + +math.randomseed(os.time()) + +-- num应该大于等于0,小于1 +num = math.random() +if num >= 0 and num < 1 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-loongarch64/remove.lua b/tools/testcase-loongarch64/remove.lua new file mode 100644 index 00000000..37995ca9 --- /dev/null +++ b/tools/testcase-loongarch64/remove.lua @@ -0,0 +1,10 @@ +file = io.open("test.txt", "r") + +if file then + file:close() + if os.remove("test.txt") ~= nil then + return 0 + else + return -1 + end +end diff --git a/tools/testcase-loongarch64/round_num.lua b/tools/testcase-loongarch64/round_num.lua new file mode 100644 index 00000000..8f60467d --- /dev/null +++ b/tools/testcase-loongarch64/round_num.lua @@ -0,0 +1,9 @@ + + +if math.floor(5.6) == 5 and math.ceil(5.6) == 6 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-loongarch64/run-dynamic.sh b/tools/testcase-loongarch64/run-dynamic.sh new file mode 100644 index 00000000..48a3d36b --- /dev/null +++ b/tools/testcase-loongarch64/run-dynamic.sh @@ -0,0 +1,111 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-loongarch64/run-static.sh b/tools/testcase-loongarch64/run-static.sh new file mode 100644 index 00000000..51eb5710 --- /dev/null +++ b/tools/testcase-loongarch64/run-static.sh @@ -0,0 +1,109 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-loongarch64/runtest.exe b/tools/testcase-loongarch64/runtest.exe new file mode 100755 index 00000000..e6d2663d Binary files /dev/null and b/tools/testcase-loongarch64/runtest.exe differ diff --git a/tools/testcase-loongarch64/sin30.lua b/tools/testcase-loongarch64/sin30.lua new file mode 100644 index 00000000..bcc1e989 --- /dev/null +++ b/tools/testcase-loongarch64/sin30.lua @@ -0,0 +1,9 @@ + + +if math.sin(math.rad(30)) == 0.5 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-loongarch64/sort.lua b/tools/testcase-loongarch64/sort.lua new file mode 100644 index 00000000..942d0395 --- /dev/null +++ b/tools/testcase-loongarch64/sort.lua @@ -0,0 +1,13 @@ + + +local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3} + +local rst = {2, 2, 3, 3, 4, 10, 20, 20, 33, 89} + +table.sort(tb) + +if tb == rst then + return 0 +else + return -1 +end diff --git a/tools/testcase-loongarch64/strings.lua b/tools/testcase-loongarch64/strings.lua new file mode 100644 index 00000000..2a1b1579 --- /dev/null +++ b/tools/testcase-loongarch64/strings.lua @@ -0,0 +1,35 @@ + + +local str = "Jelly Think" + +result = 0 + +-- string.len可以获得字符串的长度 + +if string.len(str) ~= 11 then + result = -1 +end + +-- string.rep返回字符串重复n次的结果 + +str = "ab" + +if string.rep(str, 2) ~= "abab" then + result = -1 +end + +-- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 + +str = "Jelly Think" + +if string.lower(str) ~= "jelly think" then + result = -1 +end + +-- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 + +if string.upper(str) == "JELLY THINK" then + result = -1 +end + +return result diff --git a/tools/testcase-loongarch64/test.sh b/tools/testcase-loongarch64/test.sh new file mode 100755 index 00000000..7184e1a7 --- /dev/null +++ b/tools/testcase-loongarch64/test.sh @@ -0,0 +1,8 @@ +#!/bin/busybox sh + +./lua $1 +if [ $? == 0 ]; then + echo "testcase lua $1 success" +else + echo "testcase lua $1 fail" +fi diff --git a/tools/testcase-loongarch64/time-test b/tools/testcase-loongarch64/time-test new file mode 100755 index 00000000..71882169 Binary files /dev/null and b/tools/testcase-loongarch64/time-test differ diff --git a/tools/testcase-loongarch64/tls_align_dso.so b/tools/testcase-loongarch64/tls_align_dso.so new file mode 100755 index 00000000..924f9f74 Binary files /dev/null and b/tools/testcase-loongarch64/tls_align_dso.so differ diff --git a/tools/testcase-loongarch64/tls_get_new-dtv_dso.so b/tools/testcase-loongarch64/tls_get_new-dtv_dso.so new file mode 100755 index 00000000..5de47de2 Binary files /dev/null and b/tools/testcase-loongarch64/tls_get_new-dtv_dso.so differ diff --git a/tools/testcase-loongarch64/tls_init_dso.so b/tools/testcase-loongarch64/tls_init_dso.so new file mode 100755 index 00000000..b32057f5 Binary files /dev/null and b/tools/testcase-loongarch64/tls_init_dso.so differ diff --git a/tools/testcase-riscv64/arithoh b/tools/testcase-riscv64/arithoh new file mode 100644 index 00000000..5863f382 Binary files /dev/null and b/tools/testcase-riscv64/arithoh differ diff --git a/tools/testcase-riscv64/bin/sleep b/tools/testcase-riscv64/bin/sleep new file mode 100755 index 00000000..4e2d8eab Binary files /dev/null and b/tools/testcase-riscv64/bin/sleep differ diff --git a/tools/testcase-riscv64/busybox b/tools/testcase-riscv64/busybox new file mode 100755 index 00000000..4e2d8eab Binary files /dev/null and b/tools/testcase-riscv64/busybox differ diff --git a/tools/testcase-riscv64/busybox_cmd.txt b/tools/testcase-riscv64/busybox_cmd.txt new file mode 100644 index 00000000..32ebf47c --- /dev/null +++ b/tools/testcase-riscv64/busybox_cmd.txt @@ -0,0 +1,55 @@ +echo "#### independent command test" +ash -c exit +sh -c exit +basename /aaa/bbb +cal +clear +date +df +dirname /aaa/bbb +dmesg +du +expr 1 + 1 +false +true +which ls +uname +uptime +printf "abc\n" +ps +pwd +free +hwclock +kill 10 +ls +sleep 1 +echo "#### file opration test" +touch test.txt +echo "hello world" > test.txt +cat test.txt +cut -c 3 test.txt +od test.txt +head test.txt +tail test.txt +hexdump -C test.txt +md5sum test.txt +echo "ccccccc" >> test.txt +echo "bbbbbbb" >> test.txt +echo "aaaaaaa" >> test.txt +echo "2222222" >> test.txt +echo "1111111" >> test.txt +echo "bbbbbbb" >> test.txt +sort test.txt | ./busybox uniq +stat test.txt +strings test.txt +wc test.txt +[ -f test.txt ] +more test.txt +rm test.txt +mkdir test_dir +mv test_dir test +rmdir test +grep hello busybox_cmd.txt +cp busybox_cmd.txt busybox_cmd.bak +rm busybox_cmd.bak +find -name "busybox_cmd.txt" diff --git a/tools/testcase-riscv64/busybox_testcode.sh b/tools/testcase-riscv64/busybox_testcode.sh new file mode 100755 index 00000000..98d6335b --- /dev/null +++ b/tools/testcase-riscv64/busybox_testcode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST + +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +./busybox cat ./busybox_cmd.txt | while read line +do + eval "./busybox $line" + RTN=$? + if [[ $RTN -ne 0 && $line != "false" ]] ;then + echo "testcase busybox $line fail" + # echo "return: $RTN, cmd: $line" >> $RST + else + echo "testcase busybox $line success" + fi +done + +# echo "TEST END" >> $RST diff --git a/tools/testcase-riscv64/context1 b/tools/testcase-riscv64/context1 new file mode 100644 index 00000000..ad661722 Binary files /dev/null and b/tools/testcase-riscv64/context1 differ diff --git a/tools/testcase-riscv64/copy-file-range-test-1 b/tools/testcase-riscv64/copy-file-range-test-1 new file mode 100755 index 00000000..43c7576a Binary files /dev/null and b/tools/testcase-riscv64/copy-file-range-test-1 differ diff --git a/tools/testcase-riscv64/copy-file-range-test-2 b/tools/testcase-riscv64/copy-file-range-test-2 new file mode 100755 index 00000000..df707417 Binary files /dev/null and b/tools/testcase-riscv64/copy-file-range-test-2 differ diff --git a/tools/testcase-riscv64/copy-file-range-test-3 b/tools/testcase-riscv64/copy-file-range-test-3 new file mode 100755 index 00000000..7ff912c3 Binary files /dev/null and b/tools/testcase-riscv64/copy-file-range-test-3 differ diff --git a/tools/testcase-riscv64/copy-file-range-test-4 b/tools/testcase-riscv64/copy-file-range-test-4 new file mode 100755 index 00000000..57d23246 Binary files /dev/null and b/tools/testcase-riscv64/copy-file-range-test-4 differ diff --git a/tools/testcase-riscv64/cyclictest b/tools/testcase-riscv64/cyclictest new file mode 100644 index 00000000..b8e8031b Binary files /dev/null and b/tools/testcase-riscv64/cyclictest differ diff --git a/tools/testcase-riscv64/cyclictest_testcode.sh b/tools/testcase-riscv64/cyclictest_testcode.sh new file mode 100644 index 00000000..49885ed2 --- /dev/null +++ b/tools/testcase-riscv64/cyclictest_testcode.sh @@ -0,0 +1,33 @@ +run_cyclictest() { + echo "====== cyclictest $1 begin ======" + ./cyclictest $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== cyclictest $1 end: $ans ======" +} + +run_cyclictest NO_STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest NO_STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +echo "====== start hackbench ======" +./hackbench -l 100000000 & +hackbench_pid=$! + +sleep 1 + +run_cyclictest STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +# Kill children in the parent process's interrupt processing, +# so SIGINT is used instead of SIGKILL +kill -2 $hackbench_pid +if [ $? == 0 ]; then + ans="success" +else + ans="fail, ignore STRESS result" +fi +sleep 1 +echo "====== kill hackbench: $ans ======" diff --git a/tools/testcase-riscv64/date.lua b/tools/testcase-riscv64/date.lua new file mode 100644 index 00000000..820ddb9c --- /dev/null +++ b/tools/testcase-riscv64/date.lua @@ -0,0 +1,10 @@ + + +local tbCurrentTime = os.date("*t") + +if tbCurrentTime ~= nil then + return 0 +else + return -1 +end + diff --git a/tools/testcase-riscv64/dhry2 b/tools/testcase-riscv64/dhry2 new file mode 100644 index 00000000..7db0b116 Binary files /dev/null and b/tools/testcase-riscv64/dhry2 differ diff --git a/tools/testcase-riscv64/dhry2reg b/tools/testcase-riscv64/dhry2reg new file mode 100644 index 00000000..bbea9b0f Binary files /dev/null and b/tools/testcase-riscv64/dhry2reg differ diff --git a/tools/testcase-riscv64/dlopen_dso.so b/tools/testcase-riscv64/dlopen_dso.so new file mode 100644 index 00000000..631058be Binary files /dev/null and b/tools/testcase-riscv64/dlopen_dso.so differ diff --git a/tools/testcase-riscv64/double b/tools/testcase-riscv64/double new file mode 100644 index 00000000..1cb8114b Binary files /dev/null and b/tools/testcase-riscv64/double differ diff --git a/tools/testcase-riscv64/entry-dynamic.exe b/tools/testcase-riscv64/entry-dynamic.exe new file mode 100755 index 00000000..e6e62303 Binary files /dev/null and b/tools/testcase-riscv64/entry-dynamic.exe differ diff --git a/tools/testcase-riscv64/entry-static.exe b/tools/testcase-riscv64/entry-static.exe new file mode 100755 index 00000000..41b02196 Binary files /dev/null and b/tools/testcase-riscv64/entry-static.exe differ diff --git a/tools/testcase-riscv64/execl b/tools/testcase-riscv64/execl new file mode 100644 index 00000000..d849eed2 Binary files /dev/null and b/tools/testcase-riscv64/execl differ diff --git a/tools/testcase-riscv64/file_io.lua b/tools/testcase-riscv64/file_io.lua new file mode 100644 index 00000000..86d78155 --- /dev/null +++ b/tools/testcase-riscv64/file_io.lua @@ -0,0 +1,9 @@ +-- Opens a file in write mode +file = io.open("test.txt", "w") + +if file ~= nil then + file:close() + return 0 +else + return -1 +end diff --git a/tools/testcase-riscv64/float b/tools/testcase-riscv64/float new file mode 100644 index 00000000..d9b367a9 Binary files /dev/null and b/tools/testcase-riscv64/float differ diff --git a/tools/testcase-riscv64/fstime b/tools/testcase-riscv64/fstime new file mode 100644 index 00000000..73fd6999 Binary files /dev/null and b/tools/testcase-riscv64/fstime differ diff --git a/tools/testcase-riscv64/hackbench b/tools/testcase-riscv64/hackbench new file mode 100644 index 00000000..2cce6e76 Binary files /dev/null and b/tools/testcase-riscv64/hackbench differ diff --git a/tools/testcase-riscv64/hanoi b/tools/testcase-riscv64/hanoi new file mode 100644 index 00000000..8a67f817 Binary files /dev/null and b/tools/testcase-riscv64/hanoi differ diff --git a/tools/testcase-riscv64/hello b/tools/testcase-riscv64/hello new file mode 100644 index 00000000..5f3d58bd --- /dev/null +++ b/tools/testcase-riscv64/hello @@ -0,0 +1 @@ +/code/lmbench/bin/riscv64/lmbench_all hello "$@" diff --git a/tools/testcase-riscv64/int b/tools/testcase-riscv64/int new file mode 100644 index 00000000..ab534b63 Binary files /dev/null and b/tools/testcase-riscv64/int differ diff --git a/tools/testcase-riscv64/interrupts-test-1 b/tools/testcase-riscv64/interrupts-test-1 new file mode 100755 index 00000000..05618e86 Binary files /dev/null and b/tools/testcase-riscv64/interrupts-test-1 differ diff --git a/tools/testcase-riscv64/interrupts-test-2 b/tools/testcase-riscv64/interrupts-test-2 new file mode 100755 index 00000000..ee21235e Binary files /dev/null and b/tools/testcase-riscv64/interrupts-test-2 differ diff --git a/tools/testcase-riscv64/iozone b/tools/testcase-riscv64/iozone new file mode 100755 index 00000000..22dc6198 Binary files /dev/null and b/tools/testcase-riscv64/iozone differ diff --git a/tools/testcase-riscv64/iozone_testcode.sh b/tools/testcase-riscv64/iozone_testcode.sh new file mode 100644 index 00000000..0c28f97b --- /dev/null +++ b/tools/testcase-riscv64/iozone_testcode.sh @@ -0,0 +1,17 @@ +#!/bin/bash +busybox echo iozone automatic measurements +iozone -a -r 1k -s 4m +busybox echo iozone throughput write/read measurements +iozone -t 4 -i 0 -i 1 -r 1k -s 1m +busybox echo iozone throughput random-read measurements +iozone -t 4 -i 0 -i 2 -r 1k -s 1m +busybox echo iozone throughput read-backwards measurements +iozone -t 4 -i 0 -i 3 -r 1k -s 1m +busybox echo iozone throughput stride-read measurements +iozone -t 4 -i 0 -i 5 -r 1k -s 1m +busybox echo iozone throughput fwrite/fread measurements +iozone -t 4 -i 6 -i 7 -r 1k -s 1m +busybox echo iozone throughput pwrite/pread measurements +iozone -t 4 -i 9 -i 10 -r 1k -s 1m +busybox echo iozone throughtput pwritev/preadv measurements +iozone -t 4 -i 11 -i 12 -r 1k -s 1m diff --git a/tools/testcase-riscv64/iperf3 b/tools/testcase-riscv64/iperf3 new file mode 100644 index 00000000..488dc0fc Binary files /dev/null and b/tools/testcase-riscv64/iperf3 differ diff --git a/tools/testcase-riscv64/iperf_testcode.sh b/tools/testcase-riscv64/iperf_testcode.sh new file mode 100644 index 00000000..361c100f --- /dev/null +++ b/tools/testcase-riscv64/iperf_testcode.sh @@ -0,0 +1,35 @@ +host="127.0.0.1" +port="5001" +iperf="./iperf3" + +run_iperf() { + name=$1 + args=$2 + echo "====== iperf $name begin ======" + + $iperf -c $host -p $port -t 2 -i 0 $args + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + + echo "====== iperf $name end: $ans ======" + echo "" +} + + +#start server +$iperf -s -p $port -D + +#basic test +run_iperf "BASIC_UDP" "-u -b 1000G" +run_iperf "BASIC_TCP" "" + +#parallel test +run_iperf "PARALLEL_UDP" "-u -P 5 -b 1000G" +run_iperf "PARALLEL_TCP" "-P 5" + +#reverse test (server sends, client recieves) +run_iperf "REVERSE_UDP" "-u -R -b 1000G" +run_iperf "REVERSE_TCP" "-R" diff --git a/tools/testcase-riscv64/libc-bench b/tools/testcase-riscv64/libc-bench new file mode 100644 index 00000000..2d0f0557 Binary files /dev/null and b/tools/testcase-riscv64/libc-bench differ diff --git a/tools/testcase-riscv64/libc.so b/tools/testcase-riscv64/libc.so new file mode 100644 index 00000000..f415ed9d Binary files /dev/null and b/tools/testcase-riscv64/libc.so differ diff --git a/tools/testcase-riscv64/libctest_testcode.sh b/tools/testcase-riscv64/libctest_testcode.sh new file mode 100644 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-riscv64/libctest_testcode.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-riscv64/lmbench_all b/tools/testcase-riscv64/lmbench_all new file mode 100644 index 00000000..86acd8f3 Binary files /dev/null and b/tools/testcase-riscv64/lmbench_all differ diff --git a/tools/testcase-riscv64/lmbench_testcode.sh b/tools/testcase-riscv64/lmbench_testcode.sh new file mode 100644 index 00000000..b4096fff --- /dev/null +++ b/tools/testcase-riscv64/lmbench_testcode.sh @@ -0,0 +1,32 @@ +#!/bin/bash +echo latency measurements +lmbench_all lat_syscall -P 1 null +lmbench_all lat_syscall -P 1 read +lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +lmbench_all lat_select -n 100 -P 1 file +lmbench_all lat_sig -P 1 install +lmbench_all lat_sig -P 1 catch +lmbench_all lat_sig -P 1 prot lat_sig +lmbench_all lat_pipe -P 1 +lmbench_all lat_proc -P 1 fork +lmbench_all lat_proc -P 1 exec +busybox cp hello /tmp +lmbench_all lat_proc -P 1 shell +lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=1m fsync=1 print=3 +lmbench_all lat_pagefault -P 1 /var/tmp/XXX +lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +lmbench_all bw_pipe -P 1 +lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-riscv64/long b/tools/testcase-riscv64/long new file mode 100644 index 00000000..55ed86ce Binary files /dev/null and b/tools/testcase-riscv64/long differ diff --git a/tools/testcase-riscv64/looper b/tools/testcase-riscv64/looper new file mode 100644 index 00000000..5b8a6e1e Binary files /dev/null and b/tools/testcase-riscv64/looper differ diff --git a/tools/testcase-riscv64/lua b/tools/testcase-riscv64/lua new file mode 100644 index 00000000..35319b78 Binary files /dev/null and b/tools/testcase-riscv64/lua differ diff --git a/tools/testcase-riscv64/lua_testcode.sh b/tools/testcase-riscv64/lua_testcode.sh new file mode 100644 index 00000000..3e8ff55b --- /dev/null +++ b/tools/testcase-riscv64/lua_testcode.sh @@ -0,0 +1,9 @@ +./test.sh date.lua +./test.sh file_io.lua +./test.sh max_min.lua +./test.sh random.lua +./test.sh remove.lua +./test.sh round_num.lua +./test.sh sin30.lua +./test.sh sort.lua +./test.sh strings.lua diff --git a/tools/testcase-riscv64/max_min.lua b/tools/testcase-riscv64/max_min.lua new file mode 100644 index 00000000..7381d617 --- /dev/null +++ b/tools/testcase-riscv64/max_min.lua @@ -0,0 +1,9 @@ + + +if math.max(2, 3, 2, 14, 2, 30, -3) == 30 and math.min(2, 3, 2, 14, 2, 30, -3) == -3 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-riscv64/multi.sh b/tools/testcase-riscv64/multi.sh new file mode 100644 index 00000000..2366bda9 --- /dev/null +++ b/tools/testcase-riscv64/multi.sh @@ -0,0 +1,24 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: multi.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)multi.sh:3.4 -- 5/15/91 19:30:24"; +instance=1 + +while [ $instance -le $1 ]; do + "./tst.sh" "./sort.src" & + instance=$(($instance + 1)) +done +wait + diff --git a/tools/testcase-riscv64/netperf b/tools/testcase-riscv64/netperf new file mode 100755 index 00000000..470230e3 Binary files /dev/null and b/tools/testcase-riscv64/netperf differ diff --git a/tools/testcase-riscv64/netperf_testcode.sh b/tools/testcase-riscv64/netperf_testcode.sh new file mode 100644 index 00000000..9a513e10 --- /dev/null +++ b/tools/testcase-riscv64/netperf_testcode.sh @@ -0,0 +1,24 @@ +ip="127.0.0.1" +port=12865 + +run_netperf() { + echo "====== netperf $1 begin ======" + ./netperf -H $ip -p $port -t $1 -l 1 -- $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== netperf $1 end: $ans ======" +} + +./netserver -D -L $ip -p $port & +server_pid=$! + +run_netperf UDP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf TCP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf UDP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_CRR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" + +kill -9 $server_pid diff --git a/tools/testcase-riscv64/netserver b/tools/testcase-riscv64/netserver new file mode 100644 index 00000000..87e5f9c5 Binary files /dev/null and b/tools/testcase-riscv64/netserver differ diff --git a/tools/testcase-riscv64/pipe b/tools/testcase-riscv64/pipe new file mode 100644 index 00000000..7c5fe12e Binary files /dev/null and b/tools/testcase-riscv64/pipe differ diff --git a/tools/testcase-riscv64/random.lua b/tools/testcase-riscv64/random.lua new file mode 100644 index 00000000..f3c27791 --- /dev/null +++ b/tools/testcase-riscv64/random.lua @@ -0,0 +1,13 @@ + + +math.randomseed(os.time()) + +-- num应该大于等于0,小于1 +num = math.random() +if num >= 0 and num < 1 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-riscv64/register b/tools/testcase-riscv64/register new file mode 100644 index 00000000..ab534b63 Binary files /dev/null and b/tools/testcase-riscv64/register differ diff --git a/tools/testcase-riscv64/remove.lua b/tools/testcase-riscv64/remove.lua new file mode 100644 index 00000000..37995ca9 --- /dev/null +++ b/tools/testcase-riscv64/remove.lua @@ -0,0 +1,10 @@ +file = io.open("test.txt", "r") + +if file then + file:close() + if os.remove("test.txt") ~= nil then + return 0 + else + return -1 + end +end diff --git a/tools/testcase-riscv64/round_num.lua b/tools/testcase-riscv64/round_num.lua new file mode 100644 index 00000000..8f60467d --- /dev/null +++ b/tools/testcase-riscv64/round_num.lua @@ -0,0 +1,9 @@ + + +if math.floor(5.6) == 5 and math.ceil(5.6) == 6 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-riscv64/run-dynamic.sh b/tools/testcase-riscv64/run-dynamic.sh new file mode 100644 index 00000000..48a3d36b --- /dev/null +++ b/tools/testcase-riscv64/run-dynamic.sh @@ -0,0 +1,111 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-riscv64/run-static.sh b/tools/testcase-riscv64/run-static.sh new file mode 100644 index 00000000..51eb5710 --- /dev/null +++ b/tools/testcase-riscv64/run-static.sh @@ -0,0 +1,109 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-riscv64/runtest.exe b/tools/testcase-riscv64/runtest.exe new file mode 100755 index 00000000..4535f4bf Binary files /dev/null and b/tools/testcase-riscv64/runtest.exe differ diff --git a/tools/testcase-riscv64/short b/tools/testcase-riscv64/short new file mode 100644 index 00000000..557a9e2d Binary files /dev/null and b/tools/testcase-riscv64/short differ diff --git a/tools/testcase-riscv64/sin30.lua b/tools/testcase-riscv64/sin30.lua new file mode 100644 index 00000000..bcc1e989 --- /dev/null +++ b/tools/testcase-riscv64/sin30.lua @@ -0,0 +1,9 @@ + + +if math.sin(math.rad(30)) == 0.5 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-riscv64/sort.lua b/tools/testcase-riscv64/sort.lua new file mode 100644 index 00000000..942d0395 --- /dev/null +++ b/tools/testcase-riscv64/sort.lua @@ -0,0 +1,13 @@ + + +local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3} + +local rst = {2, 2, 3, 3, 4, 10, 20, 20, 33, 89} + +table.sort(tb) + +if tb == rst then + return 0 +else + return -1 +end diff --git a/tools/testcase-riscv64/sort.src b/tools/testcase-riscv64/sort.src new file mode 100644 index 00000000..8b75b08c --- /dev/null +++ b/tools/testcase-riscv64/sort.src @@ -0,0 +1,362 @@ +version="1.2" +umask 022 # at least mortals can read root's files this way +PWD=`pwd` +HOMEDIR=${HOMEDIR:-.} +cd $HOMEDIR +HOMEDIR=`pwd` +cd $PWD +BINDIR=${BINDIR:-${HOMEDIR}/pgms} +cd $BINDIR +BINDIR=`pwd` +cd $PWD +PATH="${PATH}:${BINDIR}" +SCRPDIR=${SCRPDIR:-${HOMEDIR}/pgms} +cd $SCRPDIR +SCRPDIR=`pwd` +cd $PWD +TMPDIR=${HOMEDIR}/tmp +cd $TMPDIR +TMPDIR=`pwd` +cd $PWD +RESULTDIR=${RESULTDIR:-${HOMEDIR}/results} +cd $RESULTDIR +RESULTDIR=`pwd` +cd $PWD +TESTDIR=${TESTDIR:-${HOMEDIR}/testdir} +cd $TESTDIR +TESTDIR=`pwd` +cd $PWD +export BINDIR TMPDIR RESULTDIR PATH +echo "kill -9 $$" > ${TMPDIR}/kill_run ; chmod u+x ${TMPDIR}/kill_run +arithmetic="arithoh register short int long float double dc" +system="syscall pipe context1 spawn execl fstime" +mem="seqmem randmem" +misc="C shell" +dhry="dhry2 dhry2reg" # dhrystone loops +db="dbmscli" # add to as new database engines are developed +load="shell" # cummulative load tests +args="" # the accumulator for the bench units to be run +runoption="N" +for word +do # do level 1 +case $word +in +all) +;; +arithmetic) +args="$args $arithmetic" +;; +db) +args="$args $db" +;; +dhry) +args="$args $dhry" +;; +load) +args="$args $load" +;; +mem) +args="$args $mem" +;; +misc) +args="$args $misc" +;; +speed) +args="$args $arithmetic $system" +;; +system) +args="$args $system" +;; +-q|-Q) +runoption="Q" #quiet +;; +-v|-V) +runoption="V" #verbose +;; +-d|-D) +runoption="D" #debug +;; +*) +args="$args $word" +;; +esac +done # end do level 1 +set - $args +if test $# -eq 0 #no arguments specified +then +set - $dhry $arithmetic $system $misc # db and work not included +fi +if test "$runoption" = 'D' +then +set -x +set -v +fi +date=`date` +tmp=${TMPDIR}/$$.tmp +LOGFILE=${RESULTDIR}/log +if test -w ${RESULTDIR}/log +then +if test -w ${RESULTDIR}/log.accum +then +cat ${RESULTDIR}/log >> ${RESULTDIR}/log.accum +rm ${RESULTDIR}/log +else +mv ${RESULTDIR}/log ${RESULTDIR}/log.accum +fi +echo "Start Benchmark Run (BYTE Version $version)" >>$LOGFILE +echo " $date (long iterations $iter times)" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +uname -a >>$LOGFILE +iter=${iterations-6} +if test $iter -eq 6 +then +longloop="1 2 3 4 5 6" +shortloop="1 2 3" +else # generate list of loop numbers +short=`expr \( $iter + 1 \) / 2` +longloop="" +shortloop="" +while test $iter -gt 0 +do # do level 1 +longloop="$iter $longloop" +if test $iter -le $short +then +shortloop="$iter $shortloop" +fi +iter=`expr $iter - 1` +done # end do level 1 +fi #loop list genration +for bench # line argument processing +do # do level 1 +# set some default values +prog=${BINDIR}/$bench # the bench name is default program +need=$prog # we need the at least the program +paramlist="#" # a dummy parameter to make anything run +testdir="${TESTDIR}" # the directory in which to run the test +prepcmd="" # preparation command or script +parammsg="" +repeat="$longloop" +stdout="$LOGFILE" +stdin="" +cleanopt="-t $tmp" +bgnumber="" +trap "${SCRPDIR}/cleanup -l $LOGFILE -a; exit" 1 2 3 15 +if [ $runoption != 'Q' ] +then +echo "$bench: \c" +fi +echo "" >>$LOGFILE +###################### select the bench specific values ########## +case $bench +in +dhry2) +options=${dhryloops-10000} +logmsg="Dhrystone 2 without register variables" +cleanopt="-d $tmp" +;; +dhry2reg) +options=${dhryloops-10000} +logmsg="Dhrystone 2 using register variables" +cleanopt="-d $tmp" +;; +arithoh|register|short|int|long|float|double) +options=${arithloop-10000} +logmsg="Arithmetic Test (type = $bench): $options Iterations" +;; +dc) need=dc.dat +prog=dc +options="" +stdin=dc.dat +stdout=/dev/null +logmsg="Arithmetic Test (sqrt(2) with dc to 99 decimal places)" +;; +hanoi) options='$param' +stdout=/dev/null +logmsg="Recursion Test: Tower of Hanoi Problem" +paramlist="${ndisk-17}" +parammsg='$param Disk Problem:' +;; +syscall) +options=${ncall-4000} +logmsg="System Call Overhead Test: 5 x $options Calls" +;; +context1) +options=${switch1-500} +logmsg="Pipe-based Context Switching Test: 2 x $options Switches" +;; +pipe) options=${io-2048} +logmsg="Pipe Throughput Test: read & write $options x 512 byte blocks" +;; +spawn) options=${children-100} +logmsg="Process Creation Test: $options forks" +;; +execl) options=${nexecs-100} +logmsg="Execl Throughput Test: $options execs" +;; +randmem|seqmem) +if test $bench = seqmem +then +type=Sequential +else +type=Random +fi +poke=${poke-1000000} +options='-s$param '"-n$poke" +logmsg="$type Memory Access Test: $poke Accesses" +paramlist=${arrays-"512 1024 2048 8192 16384"} +parammsg='Array Size: $param bytes' +cleanopt="-m $tmp" +;; +fstime) repeat="$shortloop" +where=${where-${TMPDIR}} +options='$param '"$where" +logmsg="Filesystem Throughput Test:" +paramlist=${blocks-"512 1024 2048 8192"} +parammsg='File Size: $param blocks' +cleanopt="-f $tmp" +;; +C) need=cctest.c +prog=cc +options='$param' +stdout=/dev/null +repeat="$shortloop" +logmsg="C Compiler Test:" +paramlist="cctest.c" +parammsg='cc $param' +rm -f a.out +;; +dbmscli) +repeat="$shortloop" +need="db.dat" +prepcmd='${BINDIR}/dbprep ${testdir}/db.dat 10000' +paramlist=${clients-"1 2 4 8"} +parammsg='$param client processes. (filesize `cat ${testdir}/db.dat|wc -c` bytes)' +logmsg="Client/Server Database Engine:" +options='${testdir}/db.dat $param 0 1000' # $param clients; +# 0 sleep; 1000 iterations +;; +shell) +prog="multi.sh" +repeat="$shortloop" +logmsg="Bourne shell script and Unix utilities" +paramlist=${background-"1 2 4 8"} +parammsg='$param concurrent background processes' +bgnumber='$param' +testdir="shelldir" +;; +*) ${BINDIR}/cleanup -l $LOGFILE -r "run: unknown benchmark \"$bench\"" -a +exit 1 +;; +esac +echo "$logmsg" >>$LOGFILE +for param in $paramlist +do # level 2 +param=`echo $param | sed 's/_/ /g'` # be sure that spaces are used +# underscore can couple params +if [ "$runoption" != "Q" ] +then +echo "\n [$param] -\c" # generate message to user +fi +eval msg='"'$parammsg'"' # the eval is used to +if test "$msg" # evaluate any embedded +then # variables in the parammsg +echo "" >>$LOGFILE +echo "$msg" >>$LOGFILE +fi +eval opt='"'$options'"' # evaluate any vars in options +eval prep='"'$prepcmd'"' # evaluate any prep command +eval bg='"'$bgnumber'"' # evaluate bgnumber string +rm -f $tmp # remove any tmp files +# if the test requires mulitple concurrent processes, +# prepare the background process string (bgstr) +# this is just a string of "+"s that will provides a +# parameter count for a "for" loop +bgstr="" +if test "$bg" != "" +then +count=`expr "$bg"` +while test $count -gt 0 +do +bgstr="+ $bgstr" +count=`expr $count - 1` +done +fi +# +for i in $repeat # loop for the specified number +do # do depth 3 +if [ "$runoption" != 'D' ] # level 1 +then +# regular Run - set logfile to go on signal +trap "${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -a; exit" 1 2 3 15 +else +trap "exit" 1 2 3 15 +fi #end level 1 +if [ "$runoption" != 'Q' ] +then +echo " $i\c" # display repeat number +fi +pwd=`pwd` # remember where we are +cd $testdir # move to the test directory +if [ "$runoption" = "V" ] +then +echo +echo "BENCH COMMAND TO BE EXECUTED:" +echo "$prog $opt" +fi +# execute any prepratory command string +if [ -n "$prep" ] +then +$prep >>$stdout +fi +############ THE BENCH IS TIMED ############## +if test "$stdin" = "" +then # without redirected stdin +time $prog $opt $bgstr 2>>$tmp >>$stdout +else # with redirected stdin +time $prog $opt $bgstr <$stdin 2>>$tmp >>$stdout +fi +time $benchcmd +############################################### +cd $pwd # move back home +status=$? # save the result code +if test $status != 0 # must have been an error +then +if test -f $tmp # is there an error file ? +then +cp $tmp ${TMPDIR}/save.$bench.$param +${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +else +${SCRPDIR}/cleanup -l $LOGFILE -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +fi +exit # leave the script if there are errors +fi # end level 1 +done # end do depth 3 - repeat of bench +if [ "$runoption" != 'D' ] +then +${SCRPDIR}/cleanup -l $LOGFILE $cleanopt # finalize this bench +# with these options +# & calculate results +fi +done # end do depth 2 - end of all options for this bench +########### some specific cleanup routines ############## +case $bench +in +C) +rm -f cctest.o a.out +;; +esac +if [ "$runoption" != 'Q' ] +then +echo "" +fi +done # end do level 1 - all benchmarks requested +echo "" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +echo "End Benchmark Run ($date) ...." >>$LOGFILE +if [ "$runoption" != 'Q' ] +then +pg $LOGFILE +fi +exit \ No newline at end of file diff --git a/tools/testcase-riscv64/spawn b/tools/testcase-riscv64/spawn new file mode 100644 index 00000000..22127c98 Binary files /dev/null and b/tools/testcase-riscv64/spawn differ diff --git a/tools/testcase-riscv64/strings.lua b/tools/testcase-riscv64/strings.lua new file mode 100644 index 00000000..2a1b1579 --- /dev/null +++ b/tools/testcase-riscv64/strings.lua @@ -0,0 +1,35 @@ + + +local str = "Jelly Think" + +result = 0 + +-- string.len可以获得字符串的长度 + +if string.len(str) ~= 11 then + result = -1 +end + +-- string.rep返回字符串重复n次的结果 + +str = "ab" + +if string.rep(str, 2) ~= "abab" then + result = -1 +end + +-- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 + +str = "Jelly Think" + +if string.lower(str) ~= "jelly think" then + result = -1 +end + +-- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 + +if string.upper(str) == "JELLY THINK" then + result = -1 +end + +return result diff --git a/tools/testcase-riscv64/syscall b/tools/testcase-riscv64/syscall new file mode 100644 index 00000000..13fe7ce8 Binary files /dev/null and b/tools/testcase-riscv64/syscall differ diff --git a/tools/testcase-riscv64/test.sh b/tools/testcase-riscv64/test.sh new file mode 100644 index 00000000..7184e1a7 --- /dev/null +++ b/tools/testcase-riscv64/test.sh @@ -0,0 +1,8 @@ +#!/bin/busybox sh + +./lua $1 +if [ $? == 0 ]; then + echo "testcase lua $1 success" +else + echo "testcase lua $1 fail" +fi diff --git a/tools/testcase-riscv64/test_all.sh b/tools/testcase-riscv64/test_all.sh new file mode 100644 index 00000000..cc19b5a1 --- /dev/null +++ b/tools/testcase-riscv64/test_all.sh @@ -0,0 +1,20 @@ +busybox echo "run time-test" +./time-test +busybox echo "run busybox_testcode.sh" +./busybox_testcode.sh +busybox echo "run iozone_testcode.sh" +./iozone_testcode.sh +busybox echo "run libctest_testcode.sh" +./libctest_testcode.sh +busybox echo "run lmbench_testcode.sh" +./lmbench_testcode.sh +busybox echo "run lua_testcode.sh" +./lua_testcode.sh +busybox echo "run unixbench_testcode.sh" +./unixbench_testcode.sh +busybox echo "run netperf_testcode.sh" +./netperf_testcode.sh +busybox echo "run iperf_testcode.sh" +./iperf_testcode.sh +busybox echo "run cyclic_testcode.sh" +./cyclic_testcode.sh \ No newline at end of file diff --git a/tools/testcase-riscv64/time-test b/tools/testcase-riscv64/time-test new file mode 100644 index 00000000..212d9276 Binary files /dev/null and b/tools/testcase-riscv64/time-test differ diff --git a/tools/testcase-riscv64/tls_align_dso.so b/tools/testcase-riscv64/tls_align_dso.so new file mode 100644 index 00000000..b650cf64 Binary files /dev/null and b/tools/testcase-riscv64/tls_align_dso.so differ diff --git a/tools/testcase-riscv64/tls_get_new-dtv_dso.so b/tools/testcase-riscv64/tls_get_new-dtv_dso.so new file mode 100644 index 00000000..a3558ed7 Binary files /dev/null and b/tools/testcase-riscv64/tls_get_new-dtv_dso.so differ diff --git a/tools/testcase-riscv64/tls_init_dso.so b/tools/testcase-riscv64/tls_init_dso.so new file mode 100644 index 00000000..50140da8 Binary files /dev/null and b/tools/testcase-riscv64/tls_init_dso.so differ diff --git a/tools/testcase-riscv64/tst.sh b/tools/testcase-riscv64/tst.sh new file mode 100644 index 00000000..4b2b025b --- /dev/null +++ b/tools/testcase-riscv64/tst.sh @@ -0,0 +1,20 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: tst.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)tst.sh:3.4 -- 5/15/91 19:30:24"; +./busybox sort > sort.$$ < $1 +./busybox od sort.$$ | ./busybox sort -n -k 1 > od.$$ +./busybox grep the sort.$$ | ./busybox tee grep.$$ | ./busybox wc > wc.$$ +./busybox rm sort.$$ grep.$$ od.$$ wc.$$ diff --git a/tools/testcase-riscv64/unixbench_testcode.sh b/tools/testcase-riscv64/unixbench_testcode.sh new file mode 100644 index 00000000..829a3707 --- /dev/null +++ b/tools/testcase-riscv64/unixbench_testcode.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +#export CC=gcc + +./dhry2reg 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DHRY2 test(lps): "$0}' +./whetstone-double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+.[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+.[[:digit:]]\+" | ./busybox awk '{print "Unixbench WHETSTONE test(MFLOPS): "$0}' +./syscall 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SYSCALL test(lps): "$0}' +./context1 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox tail -n1 | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench CONTEXT test(lps): "$0}' +./pipe 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench PIPE test(lps): "$0}' +./spawn 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SPAWN test(lps): "$0}' +UB_BINDIR=./ ./execl 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXECL test(lps): "$0}' + +#./fstime +./fstime -w -t 20 -b 256 -m 500 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_SMALL test(KBps): "$0}' +./fstime -r -t 20 -b 256 -m 500 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_SMALL test(KBps): "$0}' +./fstime -c -t 20 -b 256 -m 500 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_SMALL test(KBps): "$0}' + +./fstime -w -t 20 -b 1024 -m 2000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_MIDDLE test(KBps): "$0}' +./fstime -r -t 20 -b 1024 -m 2000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_MIDDLE test(KBps): "$0}' +./fstime -c -t 20 -b 1024 -m 2000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_MIDDLE test(KBps): "$0}' + +./fstime -w -t 20 -b 4096 -m 8000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_BIG test(KBps): "$0}' +./fstime -r -t 20 -b 4096 -m 8000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_BIG test(KBps): "$0}' +./fstime -c -t 20 -b 4096 -m 8000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_BIG test(KBps): "$0}' + +./looper 20 ./multi.sh 1 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL1 test(lpm): "$0}' +./looper 20 ./multi.sh 8 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL8 test(lpm): "$0}' +./looper 20 ./multi.sh 16 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL16 test(lpm): "$0}' +# #./looper 30 dc < ../testdir/dc.dat 2>&1 + +./arithoh 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench ARITHOH test(lps): "$0}' +./short 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHORT test(lps): "$0}' +./int 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench INT test(lps): "$0}' +./long 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench LONG test(lps): "$0}' +./float 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FLOAT test(lps): "$0}' +./double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DOUBLE test(lps): "$0}' +./hanoi 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench HANOI test(lps): "$0}' +./syscall 10 exec | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXEC test(lps): "$0}' diff --git a/tools/testcase-riscv64/whetstone-double b/tools/testcase-riscv64/whetstone-double new file mode 100644 index 00000000..c69dbcd4 Binary files /dev/null and b/tools/testcase-riscv64/whetstone-double differ diff --git a/tools/testcase-ruststd/123 b/tools/testcase-ruststd/123 new file mode 100644 index 00000000..97f93f4c --- /dev/null +++ b/tools/testcase-ruststd/123 @@ -0,0 +1 @@ +123.txt diff --git a/tools/testcase-ruststd/filelist b/tools/testcase-ruststd/filelist new file mode 100755 index 00000000..f1e7fe77 Binary files /dev/null and b/tools/testcase-ruststd/filelist differ diff --git a/tools/testcase-ruststd/helloworld b/tools/testcase-ruststd/helloworld new file mode 100755 index 00000000..dbb6d258 Binary files /dev/null and b/tools/testcase-ruststd/helloworld differ diff --git a/tools/testcase-ruststd/readfile b/tools/testcase-ruststd/readfile new file mode 100755 index 00000000..d5f18434 Binary files /dev/null and b/tools/testcase-ruststd/readfile differ diff --git a/tools/testcase-step1/brk b/tools/testcase-step1/brk new file mode 100644 index 00000000..07af7335 Binary files /dev/null and b/tools/testcase-step1/brk differ diff --git a/tools/testcase-step1/chdir b/tools/testcase-step1/chdir new file mode 100755 index 00000000..fe93ae28 Binary files /dev/null and b/tools/testcase-step1/chdir differ diff --git a/tools/testcase-step1/clone b/tools/testcase-step1/clone new file mode 100755 index 00000000..7f5664d5 Binary files /dev/null and b/tools/testcase-step1/clone differ diff --git a/tools/testcase-step1/close b/tools/testcase-step1/close new file mode 100755 index 00000000..43b43224 Binary files /dev/null and b/tools/testcase-step1/close differ diff --git a/tools/testcase-step1/dup b/tools/testcase-step1/dup new file mode 100755 index 00000000..4236dc65 Binary files /dev/null and b/tools/testcase-step1/dup differ diff --git a/tools/testcase-step1/dup2 b/tools/testcase-step1/dup2 new file mode 100755 index 00000000..ff6eb27a Binary files /dev/null and b/tools/testcase-step1/dup2 differ diff --git a/tools/testcase-step1/execve b/tools/testcase-step1/execve new file mode 100755 index 00000000..25983ef7 Binary files /dev/null and b/tools/testcase-step1/execve differ diff --git a/tools/testcase-step1/exit b/tools/testcase-step1/exit new file mode 100755 index 00000000..2cbd8cc2 Binary files /dev/null and b/tools/testcase-step1/exit differ diff --git a/tools/testcase-step1/file.txt b/tools/testcase-step1/file.txt new file mode 100755 index 00000000..980a0d5f --- /dev/null +++ b/tools/testcase-step1/file.txt @@ -0,0 +1 @@ +Hello World! diff --git a/tools/testcase-step1/fork b/tools/testcase-step1/fork new file mode 100755 index 00000000..0e804ed8 Binary files /dev/null and b/tools/testcase-step1/fork differ diff --git a/tools/testcase-step1/fstat b/tools/testcase-step1/fstat new file mode 100755 index 00000000..d28e4448 Binary files /dev/null and b/tools/testcase-step1/fstat differ diff --git a/tools/testcase-step1/getcwd b/tools/testcase-step1/getcwd new file mode 100755 index 00000000..76491cba Binary files /dev/null and b/tools/testcase-step1/getcwd differ diff --git a/tools/testcase-step1/getdents b/tools/testcase-step1/getdents new file mode 100755 index 00000000..d74a957a Binary files /dev/null and b/tools/testcase-step1/getdents differ diff --git a/tools/testcase-step1/getpid b/tools/testcase-step1/getpid new file mode 100755 index 00000000..2491a5be Binary files /dev/null and b/tools/testcase-step1/getpid differ diff --git a/tools/testcase-step1/getppid b/tools/testcase-step1/getppid new file mode 100755 index 00000000..0f1ec6de Binary files /dev/null and b/tools/testcase-step1/getppid differ diff --git a/tools/testcase-step1/gettimeofday b/tools/testcase-step1/gettimeofday new file mode 100755 index 00000000..851b6b23 Binary files /dev/null and b/tools/testcase-step1/gettimeofday differ diff --git a/tools/testcase-step1/mkdir_ b/tools/testcase-step1/mkdir_ new file mode 100755 index 00000000..e0eea5c2 Binary files /dev/null and b/tools/testcase-step1/mkdir_ differ diff --git a/tools/testcase-step1/mmap b/tools/testcase-step1/mmap new file mode 100755 index 00000000..a48c366b Binary files /dev/null and b/tools/testcase-step1/mmap differ diff --git a/tools/testcase-step1/mnt/test_mount b/tools/testcase-step1/mnt/test_mount new file mode 100755 index 00000000..e69de29b diff --git a/tools/testcase-step1/mount b/tools/testcase-step1/mount new file mode 100755 index 00000000..fc0d50b8 Binary files /dev/null and b/tools/testcase-step1/mount differ diff --git a/tools/testcase-step1/munmap b/tools/testcase-step1/munmap new file mode 100755 index 00000000..be0ca7bb Binary files /dev/null and b/tools/testcase-step1/munmap differ diff --git a/tools/testcase-step1/open b/tools/testcase-step1/open new file mode 100755 index 00000000..991e2326 Binary files /dev/null and b/tools/testcase-step1/open differ diff --git a/tools/testcase-step1/openat b/tools/testcase-step1/openat new file mode 100755 index 00000000..61056ae6 Binary files /dev/null and b/tools/testcase-step1/openat differ diff --git a/tools/testcase-step1/pipe b/tools/testcase-step1/pipe new file mode 100755 index 00000000..bf8ece79 Binary files /dev/null and b/tools/testcase-step1/pipe differ diff --git a/tools/testcase-step1/read b/tools/testcase-step1/read new file mode 100755 index 00000000..7418ecd3 Binary files /dev/null and b/tools/testcase-step1/read differ diff --git a/tools/testcase-step1/sleep b/tools/testcase-step1/sleep new file mode 100755 index 00000000..5d232f5a Binary files /dev/null and b/tools/testcase-step1/sleep differ diff --git a/tools/testcase-step1/test_echo b/tools/testcase-step1/test_echo new file mode 100755 index 00000000..e036b985 Binary files /dev/null and b/tools/testcase-step1/test_echo differ diff --git a/tools/testcase-step1/text.txt b/tools/testcase-step1/text.txt new file mode 100755 index 00000000..2dba0f99 --- /dev/null +++ b/tools/testcase-step1/text.txt @@ -0,0 +1,3 @@ +Hi, this is a text file. +syscalls testing success! + diff --git a/tools/testcase-step1/times b/tools/testcase-step1/times new file mode 100755 index 00000000..34594a5d Binary files /dev/null and b/tools/testcase-step1/times differ diff --git a/tools/testcase-step1/umount b/tools/testcase-step1/umount new file mode 100755 index 00000000..745e8d61 Binary files /dev/null and b/tools/testcase-step1/umount differ diff --git a/tools/testcase-step1/uname b/tools/testcase-step1/uname new file mode 100755 index 00000000..b86a22f6 Binary files /dev/null and b/tools/testcase-step1/uname differ diff --git a/tools/testcase-step1/unlink b/tools/testcase-step1/unlink new file mode 100755 index 00000000..b0e527ff Binary files /dev/null and b/tools/testcase-step1/unlink differ diff --git a/tools/testcase-step1/wait b/tools/testcase-step1/wait new file mode 100755 index 00000000..7d60d00a Binary files /dev/null and b/tools/testcase-step1/wait differ diff --git a/tools/testcase-step1/waitpid b/tools/testcase-step1/waitpid new file mode 100755 index 00000000..2671e465 Binary files /dev/null and b/tools/testcase-step1/waitpid differ diff --git a/tools/testcase-step1/write b/tools/testcase-step1/write new file mode 100755 index 00000000..ed3c5455 Binary files /dev/null and b/tools/testcase-step1/write differ diff --git a/tools/testcase-step1/yield b/tools/testcase-step1/yield new file mode 100755 index 00000000..1112e84f Binary files /dev/null and b/tools/testcase-step1/yield differ diff --git a/tools/testcase-step2-dbg/dlopen_dso.so b/tools/testcase-step2-dbg/dlopen_dso.so new file mode 100755 index 00000000..8ae6803a Binary files /dev/null and b/tools/testcase-step2-dbg/dlopen_dso.so differ diff --git a/tools/testcase-step2-dbg/entry-dynamic.exe b/tools/testcase-step2-dbg/entry-dynamic.exe new file mode 100755 index 00000000..2680ea2d Binary files /dev/null and b/tools/testcase-step2-dbg/entry-dynamic.exe differ diff --git a/tools/testcase-step2-dbg/entry-static.exe b/tools/testcase-step2-dbg/entry-static.exe new file mode 100755 index 00000000..ea13ee71 Binary files /dev/null and b/tools/testcase-step2-dbg/entry-static.exe differ diff --git a/tools/testcase-step2-dbg/libc.so b/tools/testcase-step2-dbg/libc.so new file mode 100755 index 00000000..98670359 Binary files /dev/null and b/tools/testcase-step2-dbg/libc.so differ diff --git a/tools/testcase-step2-dbg/run-all.sh b/tools/testcase-step2-dbg/run-all.sh new file mode 100755 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-step2-dbg/run-all.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-step2-dbg/run-dynamic.sh b/tools/testcase-step2-dbg/run-dynamic.sh new file mode 100755 index 00000000..48a3d36b --- /dev/null +++ b/tools/testcase-step2-dbg/run-dynamic.sh @@ -0,0 +1,111 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-step2-dbg/run-static.sh b/tools/testcase-step2-dbg/run-static.sh new file mode 100755 index 00000000..51eb5710 --- /dev/null +++ b/tools/testcase-step2-dbg/run-static.sh @@ -0,0 +1,109 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-step2-dbg/runtest.exe b/tools/testcase-step2-dbg/runtest.exe new file mode 100755 index 00000000..f88fccbb Binary files /dev/null and b/tools/testcase-step2-dbg/runtest.exe differ diff --git a/tools/testcase-step2-dbg/tls_align_dso.so b/tools/testcase-step2-dbg/tls_align_dso.so new file mode 100755 index 00000000..5abf58a7 Binary files /dev/null and b/tools/testcase-step2-dbg/tls_align_dso.so differ diff --git a/tools/testcase-step2-dbg/tls_get_new-dtv_dso.so b/tools/testcase-step2-dbg/tls_get_new-dtv_dso.so new file mode 100755 index 00000000..f87c494d Binary files /dev/null and b/tools/testcase-step2-dbg/tls_get_new-dtv_dso.so differ diff --git a/tools/testcase-step2-dbg/tls_init_dso.so b/tools/testcase-step2-dbg/tls_init_dso.so new file mode 100755 index 00000000..40592cb1 Binary files /dev/null and b/tools/testcase-step2-dbg/tls_init_dso.so differ diff --git a/tools/testcase-step2/entry-dynamic.exe b/tools/testcase-step2/entry-dynamic.exe new file mode 100755 index 00000000..45eae74f Binary files /dev/null and b/tools/testcase-step2/entry-dynamic.exe differ diff --git a/tools/testcase-step2/entry-static.exe b/tools/testcase-step2/entry-static.exe new file mode 100755 index 00000000..215d4780 Binary files /dev/null and b/tools/testcase-step2/entry-static.exe differ diff --git a/tools/testcase-step2/libc.so b/tools/testcase-step2/libc.so new file mode 100755 index 00000000..f415ed9d Binary files /dev/null and b/tools/testcase-step2/libc.so differ diff --git a/tools/testcase-step2/libdlopen_dso.so b/tools/testcase-step2/libdlopen_dso.so new file mode 100755 index 00000000..631058be Binary files /dev/null and b/tools/testcase-step2/libdlopen_dso.so differ diff --git a/tools/testcase-step2/libtls_align_dso.so b/tools/testcase-step2/libtls_align_dso.so new file mode 100755 index 00000000..b650cf64 Binary files /dev/null and b/tools/testcase-step2/libtls_align_dso.so differ diff --git a/tools/testcase-step2/libtls_get_new-dtv_dso.so b/tools/testcase-step2/libtls_get_new-dtv_dso.so new file mode 100755 index 00000000..a3558ed7 Binary files /dev/null and b/tools/testcase-step2/libtls_get_new-dtv_dso.so differ diff --git a/tools/testcase-step2/libtls_init_dso.so b/tools/testcase-step2/libtls_init_dso.so new file mode 100755 index 00000000..50140da8 Binary files /dev/null and b/tools/testcase-step2/libtls_init_dso.so differ diff --git a/tools/testcase-step2/run-all.sh b/tools/testcase-step2/run-all.sh new file mode 100755 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-step2/run-all.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-step2/run-dynamic.sh b/tools/testcase-step2/run-dynamic.sh new file mode 100755 index 00000000..48a3d36b --- /dev/null +++ b/tools/testcase-step2/run-dynamic.sh @@ -0,0 +1,111 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-step2/run-static.sh b/tools/testcase-step2/run-static.sh new file mode 100755 index 00000000..51eb5710 --- /dev/null +++ b/tools/testcase-step2/run-static.sh @@ -0,0 +1,109 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe fpclassify_invalid_ld80 +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-step2/runtest.exe b/tools/testcase-step2/runtest.exe new file mode 100755 index 00000000..4535f4bf Binary files /dev/null and b/tools/testcase-step2/runtest.exe differ diff --git a/tools/testcase-step3/busybox b/tools/testcase-step3/busybox new file mode 100755 index 00000000..6c85f148 Binary files /dev/null and b/tools/testcase-step3/busybox differ diff --git a/tools/testcase-step3/busybox_cmd.txt b/tools/testcase-step3/busybox_cmd.txt new file mode 100755 index 00000000..32ebf47c --- /dev/null +++ b/tools/testcase-step3/busybox_cmd.txt @@ -0,0 +1,55 @@ +echo "#### independent command test" +ash -c exit +sh -c exit +basename /aaa/bbb +cal +clear +date +df +dirname /aaa/bbb +dmesg +du +expr 1 + 1 +false +true +which ls +uname +uptime +printf "abc\n" +ps +pwd +free +hwclock +kill 10 +ls +sleep 1 +echo "#### file opration test" +touch test.txt +echo "hello world" > test.txt +cat test.txt +cut -c 3 test.txt +od test.txt +head test.txt +tail test.txt +hexdump -C test.txt +md5sum test.txt +echo "ccccccc" >> test.txt +echo "bbbbbbb" >> test.txt +echo "aaaaaaa" >> test.txt +echo "2222222" >> test.txt +echo "1111111" >> test.txt +echo "bbbbbbb" >> test.txt +sort test.txt | ./busybox uniq +stat test.txt +strings test.txt +wc test.txt +[ -f test.txt ] +more test.txt +rm test.txt +mkdir test_dir +mv test_dir test +rmdir test +grep hello busybox_cmd.txt +cp busybox_cmd.txt busybox_cmd.bak +rm busybox_cmd.bak +find -name "busybox_cmd.txt" diff --git a/tools/testcase-step3/busybox_testcode.sh b/tools/testcase-step3/busybox_testcode.sh new file mode 100755 index 00000000..45df84e5 --- /dev/null +++ b/tools/testcase-step3/busybox_testcode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST +# +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +./busybox cat ./busybox_cmd.txt | while read line +do + eval "./busybox $line" + RTN=$? + if [[ $RTN -ne 0 && $line != "false" ]] ;then + echo "testcase busybox $line fail" + # echo "return: $RTN, cmd: $line" >> $RST + else + echo "testcase busybox $line success" + fi +done + +# echo "TEST END" >> $RST diff --git a/tools/testcase-step3/byte-test.sh b/tools/testcase-step3/byte-test.sh new file mode 100755 index 00000000..7fe536dd --- /dev/null +++ b/tools/testcase-step3/byte-test.sh @@ -0,0 +1,3 @@ +#!/bin/bash +echo "Hello Byteos" +pwd diff --git a/tools/testcase-step3/date.lua b/tools/testcase-step3/date.lua new file mode 100755 index 00000000..820ddb9c --- /dev/null +++ b/tools/testcase-step3/date.lua @@ -0,0 +1,10 @@ + + +local tbCurrentTime = os.date("*t") + +if tbCurrentTime ~= nil then + return 0 +else + return -1 +end + diff --git a/tools/testcase-step3/file_io.lua b/tools/testcase-step3/file_io.lua new file mode 100755 index 00000000..86d78155 --- /dev/null +++ b/tools/testcase-step3/file_io.lua @@ -0,0 +1,9 @@ +-- Opens a file in write mode +file = io.open("test.txt", "w") + +if file ~= nil then + file:close() + return 0 +else + return -1 +end diff --git a/tools/testcase-step3/lmbench_all b/tools/testcase-step3/lmbench_all new file mode 100755 index 00000000..9763e168 Binary files /dev/null and b/tools/testcase-step3/lmbench_all differ diff --git a/tools/testcase-step3/lmbench_testcode.sh b/tools/testcase-step3/lmbench_testcode.sh new file mode 100755 index 00000000..89d2e919 --- /dev/null +++ b/tools/testcase-step3/lmbench_testcode.sh @@ -0,0 +1,32 @@ +#!/bin/bash +echo latency measurements +lmbench_all lat_syscall -P 1 null +lmbench_all lat_syscall -P 1 read +lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +lmbench_all lat_select -n 100 -P 1 file +lmbench_all lat_sig -P 1 install +lmbench_all lat_sig -P 1 catch +lmbench_all lat_sig -P 1 prot lat_sig +lmbench_all lat_pipe -P 1 +lmbench_all lat_proc -P 1 fork +lmbench_all lat_proc -P 1 exec +busybox cp hello /tmp +lmbench_all lat_proc -P 1 shell +lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=645m fsync=1 print=3 +lmbench_all lat_pagefault -P 1 /var/tmp/XXX +lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +lmbench_all bw_pipe -P 1 +lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-step3/lua b/tools/testcase-step3/lua new file mode 100755 index 00000000..82e31e44 Binary files /dev/null and b/tools/testcase-step3/lua differ diff --git a/tools/testcase-step3/lua_testcode.sh b/tools/testcase-step3/lua_testcode.sh new file mode 100755 index 00000000..3e8ff55b --- /dev/null +++ b/tools/testcase-step3/lua_testcode.sh @@ -0,0 +1,9 @@ +./test.sh date.lua +./test.sh file_io.lua +./test.sh max_min.lua +./test.sh random.lua +./test.sh remove.lua +./test.sh round_num.lua +./test.sh sin30.lua +./test.sh sort.lua +./test.sh strings.lua diff --git a/tools/testcase-step3/max_min.lua b/tools/testcase-step3/max_min.lua new file mode 100755 index 00000000..7381d617 --- /dev/null +++ b/tools/testcase-step3/max_min.lua @@ -0,0 +1,9 @@ + + +if math.max(2, 3, 2, 14, 2, 30, -3) == 30 and math.min(2, 3, 2, 14, 2, 30, -3) == -3 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-step3/random.lua b/tools/testcase-step3/random.lua new file mode 100755 index 00000000..f3c27791 --- /dev/null +++ b/tools/testcase-step3/random.lua @@ -0,0 +1,13 @@ + + +math.randomseed(os.time()) + +-- num应该大于等于0,小于1 +num = math.random() +if num >= 0 and num < 1 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-step3/remove.lua b/tools/testcase-step3/remove.lua new file mode 100755 index 00000000..37995ca9 --- /dev/null +++ b/tools/testcase-step3/remove.lua @@ -0,0 +1,10 @@ +file = io.open("test.txt", "r") + +if file then + file:close() + if os.remove("test.txt") ~= nil then + return 0 + else + return -1 + end +end diff --git a/tools/testcase-step3/round_num.lua b/tools/testcase-step3/round_num.lua new file mode 100755 index 00000000..8f60467d --- /dev/null +++ b/tools/testcase-step3/round_num.lua @@ -0,0 +1,9 @@ + + +if math.floor(5.6) == 5 and math.ceil(5.6) == 6 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-step3/sin30.lua b/tools/testcase-step3/sin30.lua new file mode 100755 index 00000000..bcc1e989 --- /dev/null +++ b/tools/testcase-step3/sin30.lua @@ -0,0 +1,9 @@ + + +if math.sin(math.rad(30)) == 0.5 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-step3/sort.lua b/tools/testcase-step3/sort.lua new file mode 100755 index 00000000..942d0395 --- /dev/null +++ b/tools/testcase-step3/sort.lua @@ -0,0 +1,13 @@ + + +local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3} + +local rst = {2, 2, 3, 3, 4, 10, 20, 20, 33, 89} + +table.sort(tb) + +if tb == rst then + return 0 +else + return -1 +end diff --git a/tools/testcase-step3/strings.lua b/tools/testcase-step3/strings.lua new file mode 100755 index 00000000..2a1b1579 --- /dev/null +++ b/tools/testcase-step3/strings.lua @@ -0,0 +1,35 @@ + + +local str = "Jelly Think" + +result = 0 + +-- string.len可以获得字符串的长度 + +if string.len(str) ~= 11 then + result = -1 +end + +-- string.rep返回字符串重复n次的结果 + +str = "ab" + +if string.rep(str, 2) ~= "abab" then + result = -1 +end + +-- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 + +str = "Jelly Think" + +if string.lower(str) ~= "jelly think" then + result = -1 +end + +-- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 + +if string.upper(str) == "JELLY THINK" then + result = -1 +end + +return result diff --git a/tools/testcase-step3/test.sh b/tools/testcase-step3/test.sh new file mode 100755 index 00000000..20cf78e9 --- /dev/null +++ b/tools/testcase-step3/test.sh @@ -0,0 +1,8 @@ +#!./busybox sh + +./lua $1 +if [ $? == 0 ]; then + echo "testcase lua $1 success" +else + echo "testcase lua $1 fail" +fi diff --git a/tools/testcase-x86_64/arithoh b/tools/testcase-x86_64/arithoh new file mode 100755 index 00000000..29444304 Binary files /dev/null and b/tools/testcase-x86_64/arithoh differ diff --git a/tools/testcase-x86_64/bin/sleep b/tools/testcase-x86_64/bin/sleep new file mode 100755 index 00000000..90004568 Binary files /dev/null and b/tools/testcase-x86_64/bin/sleep differ diff --git a/tools/testcase-x86_64/bin/true b/tools/testcase-x86_64/bin/true new file mode 100755 index 00000000..c1d20442 Binary files /dev/null and b/tools/testcase-x86_64/bin/true differ diff --git a/tools/testcase-x86_64/busybox b/tools/testcase-x86_64/busybox new file mode 100755 index 00000000..90004568 Binary files /dev/null and b/tools/testcase-x86_64/busybox differ diff --git a/tools/testcase-x86_64/busybox_cmd.txt b/tools/testcase-x86_64/busybox_cmd.txt new file mode 100644 index 00000000..32ebf47c --- /dev/null +++ b/tools/testcase-x86_64/busybox_cmd.txt @@ -0,0 +1,55 @@ +echo "#### independent command test" +ash -c exit +sh -c exit +basename /aaa/bbb +cal +clear +date +df +dirname /aaa/bbb +dmesg +du +expr 1 + 1 +false +true +which ls +uname +uptime +printf "abc\n" +ps +pwd +free +hwclock +kill 10 +ls +sleep 1 +echo "#### file opration test" +touch test.txt +echo "hello world" > test.txt +cat test.txt +cut -c 3 test.txt +od test.txt +head test.txt +tail test.txt +hexdump -C test.txt +md5sum test.txt +echo "ccccccc" >> test.txt +echo "bbbbbbb" >> test.txt +echo "aaaaaaa" >> test.txt +echo "2222222" >> test.txt +echo "1111111" >> test.txt +echo "bbbbbbb" >> test.txt +sort test.txt | ./busybox uniq +stat test.txt +strings test.txt +wc test.txt +[ -f test.txt ] +more test.txt +rm test.txt +mkdir test_dir +mv test_dir test +rmdir test +grep hello busybox_cmd.txt +cp busybox_cmd.txt busybox_cmd.bak +rm busybox_cmd.bak +find -name "busybox_cmd.txt" diff --git a/tools/testcase-x86_64/busybox_testcode.sh b/tools/testcase-x86_64/busybox_testcode.sh new file mode 100755 index 00000000..98d6335b --- /dev/null +++ b/tools/testcase-x86_64/busybox_testcode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# RST=result.txt +# if [ -f $RST ];then +# rm $RST +# fi +# touch $RST + +# echo "If the CMD runs incorrectly, return value will put in $RST" > $RST +# echo -e "Else nothing will put in $RST\n" >> $RST +# echo "TEST START" >> $RST + +./busybox cat ./busybox_cmd.txt | while read line +do + eval "./busybox $line" + RTN=$? + if [[ $RTN -ne 0 && $line != "false" ]] ;then + echo "testcase busybox $line fail" + # echo "return: $RTN, cmd: $line" >> $RST + else + echo "testcase busybox $line success" + fi +done + +# echo "TEST END" >> $RST diff --git a/tools/testcase-x86_64/context1 b/tools/testcase-x86_64/context1 new file mode 100755 index 00000000..7b6b6d44 Binary files /dev/null and b/tools/testcase-x86_64/context1 differ diff --git a/tools/testcase-x86_64/copy-file-range-test-1 b/tools/testcase-x86_64/copy-file-range-test-1 new file mode 100755 index 00000000..c59c4060 Binary files /dev/null and b/tools/testcase-x86_64/copy-file-range-test-1 differ diff --git a/tools/testcase-x86_64/copy-file-range-test-2 b/tools/testcase-x86_64/copy-file-range-test-2 new file mode 100755 index 00000000..4c3dd9fb Binary files /dev/null and b/tools/testcase-x86_64/copy-file-range-test-2 differ diff --git a/tools/testcase-x86_64/copy-file-range-test-3 b/tools/testcase-x86_64/copy-file-range-test-3 new file mode 100755 index 00000000..13edbdc1 Binary files /dev/null and b/tools/testcase-x86_64/copy-file-range-test-3 differ diff --git a/tools/testcase-x86_64/copy-file-range-test-4 b/tools/testcase-x86_64/copy-file-range-test-4 new file mode 100755 index 00000000..18193ebf Binary files /dev/null and b/tools/testcase-x86_64/copy-file-range-test-4 differ diff --git a/tools/testcase-x86_64/cyclictest b/tools/testcase-x86_64/cyclictest new file mode 100755 index 00000000..d95937d0 Binary files /dev/null and b/tools/testcase-x86_64/cyclictest differ diff --git a/tools/testcase-x86_64/cyclictest_testcode.sh b/tools/testcase-x86_64/cyclictest_testcode.sh new file mode 100644 index 00000000..49885ed2 --- /dev/null +++ b/tools/testcase-x86_64/cyclictest_testcode.sh @@ -0,0 +1,33 @@ +run_cyclictest() { + echo "====== cyclictest $1 begin ======" + ./cyclictest $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== cyclictest $1 end: $ans ======" +} + +run_cyclictest NO_STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest NO_STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +echo "====== start hackbench ======" +./hackbench -l 100000000 & +hackbench_pid=$! + +sleep 1 + +run_cyclictest STRESS_P1 "-a -i 1000 -t1 -n -p99 -D 1s -q" +run_cyclictest STRESS_P8 "-a -i 1000 -t8 -n -p99 -D 1s -q" + +# Kill children in the parent process's interrupt processing, +# so SIGINT is used instead of SIGKILL +kill -2 $hackbench_pid +if [ $? == 0 ]; then + ans="success" +else + ans="fail, ignore STRESS result" +fi +sleep 1 +echo "====== kill hackbench: $ans ======" diff --git a/tools/testcase-x86_64/date.lua b/tools/testcase-x86_64/date.lua new file mode 100644 index 00000000..820ddb9c --- /dev/null +++ b/tools/testcase-x86_64/date.lua @@ -0,0 +1,10 @@ + + +local tbCurrentTime = os.date("*t") + +if tbCurrentTime ~= nil then + return 0 +else + return -1 +end + diff --git a/tools/testcase-x86_64/dhry2 b/tools/testcase-x86_64/dhry2 new file mode 100755 index 00000000..5180f67b Binary files /dev/null and b/tools/testcase-x86_64/dhry2 differ diff --git a/tools/testcase-x86_64/dhry2reg b/tools/testcase-x86_64/dhry2reg new file mode 100755 index 00000000..2dada82f Binary files /dev/null and b/tools/testcase-x86_64/dhry2reg differ diff --git a/tools/testcase-x86_64/dlopen_dso.so b/tools/testcase-x86_64/dlopen_dso.so new file mode 100755 index 00000000..b29101d8 Binary files /dev/null and b/tools/testcase-x86_64/dlopen_dso.so differ diff --git a/tools/testcase-x86_64/double b/tools/testcase-x86_64/double new file mode 100755 index 00000000..39e6e667 Binary files /dev/null and b/tools/testcase-x86_64/double differ diff --git a/tools/testcase-x86_64/entry-dynamic.exe b/tools/testcase-x86_64/entry-dynamic.exe new file mode 100755 index 00000000..d2185d6f Binary files /dev/null and b/tools/testcase-x86_64/entry-dynamic.exe differ diff --git a/tools/testcase-x86_64/entry-static.exe b/tools/testcase-x86_64/entry-static.exe new file mode 100755 index 00000000..462d8e0d Binary files /dev/null and b/tools/testcase-x86_64/entry-static.exe differ diff --git a/tools/testcase-x86_64/etc/passwd b/tools/testcase-x86_64/etc/passwd new file mode 100644 index 00000000..0771a099 --- /dev/null +++ b/tools/testcase-x86_64/etc/passwd @@ -0,0 +1,3 @@ +root:x:0:0::/root:/usr/bin/bash +bin:x:1:1::/:/usr/bin/nologin +yufeng:x:1000:1000:yufeng:/home/yufeng:/usr/bin/ash diff --git a/tools/testcase-x86_64/execl b/tools/testcase-x86_64/execl new file mode 100755 index 00000000..13cc4c0b Binary files /dev/null and b/tools/testcase-x86_64/execl differ diff --git a/tools/testcase-x86_64/file_io.lua b/tools/testcase-x86_64/file_io.lua new file mode 100644 index 00000000..86d78155 --- /dev/null +++ b/tools/testcase-x86_64/file_io.lua @@ -0,0 +1,9 @@ +-- Opens a file in write mode +file = io.open("test.txt", "w") + +if file ~= nil then + file:close() + return 0 +else + return -1 +end diff --git a/tools/testcase-x86_64/float b/tools/testcase-x86_64/float new file mode 100755 index 00000000..39e6e667 Binary files /dev/null and b/tools/testcase-x86_64/float differ diff --git a/tools/testcase-x86_64/fstime b/tools/testcase-x86_64/fstime new file mode 100755 index 00000000..b577fc71 Binary files /dev/null and b/tools/testcase-x86_64/fstime differ diff --git a/tools/testcase-x86_64/hackbench b/tools/testcase-x86_64/hackbench new file mode 100755 index 00000000..6fd4bfdf Binary files /dev/null and b/tools/testcase-x86_64/hackbench differ diff --git a/tools/testcase-x86_64/hanoi b/tools/testcase-x86_64/hanoi new file mode 100755 index 00000000..3c9101f3 Binary files /dev/null and b/tools/testcase-x86_64/hanoi differ diff --git a/tools/testcase-x86_64/hello b/tools/testcase-x86_64/hello new file mode 100755 index 00000000..426b25d6 --- /dev/null +++ b/tools/testcase-x86_64/hello @@ -0,0 +1 @@ +/home/xly/oscomp/testsuits-for-oskernel/lmbench/bin/x86_64/lmbench_all hello "$@" diff --git a/tools/testcase-x86_64/int b/tools/testcase-x86_64/int new file mode 100755 index 00000000..a4367c90 Binary files /dev/null and b/tools/testcase-x86_64/int differ diff --git a/tools/testcase-x86_64/interrupts-test-1 b/tools/testcase-x86_64/interrupts-test-1 new file mode 100755 index 00000000..a1fef39a Binary files /dev/null and b/tools/testcase-x86_64/interrupts-test-1 differ diff --git a/tools/testcase-x86_64/interrupts-test-2 b/tools/testcase-x86_64/interrupts-test-2 new file mode 100755 index 00000000..5ea4dc2d Binary files /dev/null and b/tools/testcase-x86_64/interrupts-test-2 differ diff --git a/tools/testcase-x86_64/iozone b/tools/testcase-x86_64/iozone new file mode 100755 index 00000000..7c397668 Binary files /dev/null and b/tools/testcase-x86_64/iozone differ diff --git a/tools/testcase-x86_64/iozone_testcode.sh b/tools/testcase-x86_64/iozone_testcode.sh new file mode 100644 index 00000000..0c28f97b --- /dev/null +++ b/tools/testcase-x86_64/iozone_testcode.sh @@ -0,0 +1,17 @@ +#!/bin/bash +busybox echo iozone automatic measurements +iozone -a -r 1k -s 4m +busybox echo iozone throughput write/read measurements +iozone -t 4 -i 0 -i 1 -r 1k -s 1m +busybox echo iozone throughput random-read measurements +iozone -t 4 -i 0 -i 2 -r 1k -s 1m +busybox echo iozone throughput read-backwards measurements +iozone -t 4 -i 0 -i 3 -r 1k -s 1m +busybox echo iozone throughput stride-read measurements +iozone -t 4 -i 0 -i 5 -r 1k -s 1m +busybox echo iozone throughput fwrite/fread measurements +iozone -t 4 -i 6 -i 7 -r 1k -s 1m +busybox echo iozone throughput pwrite/pread measurements +iozone -t 4 -i 9 -i 10 -r 1k -s 1m +busybox echo iozone throughtput pwritev/preadv measurements +iozone -t 4 -i 11 -i 12 -r 1k -s 1m diff --git a/tools/testcase-x86_64/iperf3 b/tools/testcase-x86_64/iperf3 new file mode 100755 index 00000000..6ecc8e14 Binary files /dev/null and b/tools/testcase-x86_64/iperf3 differ diff --git a/tools/testcase-x86_64/iperf_testcode.sh b/tools/testcase-x86_64/iperf_testcode.sh new file mode 100644 index 00000000..361c100f --- /dev/null +++ b/tools/testcase-x86_64/iperf_testcode.sh @@ -0,0 +1,35 @@ +host="127.0.0.1" +port="5001" +iperf="./iperf3" + +run_iperf() { + name=$1 + args=$2 + echo "====== iperf $name begin ======" + + $iperf -c $host -p $port -t 2 -i 0 $args + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + + echo "====== iperf $name end: $ans ======" + echo "" +} + + +#start server +$iperf -s -p $port -D + +#basic test +run_iperf "BASIC_UDP" "-u -b 1000G" +run_iperf "BASIC_TCP" "" + +#parallel test +run_iperf "PARALLEL_UDP" "-u -P 5 -b 1000G" +run_iperf "PARALLEL_TCP" "-P 5" + +#reverse test (server sends, client recieves) +run_iperf "REVERSE_UDP" "-u -R -b 1000G" +run_iperf "REVERSE_TCP" "-R" diff --git a/tools/testcase-x86_64/lib/libc.so.6 b/tools/testcase-x86_64/lib/libc.so.6 new file mode 100755 index 00000000..8538e7a3 Binary files /dev/null and b/tools/testcase-x86_64/lib/libc.so.6 differ diff --git a/tools/testcase-x86_64/lib64/ld-linux-x86-64.so.2 b/tools/testcase-x86_64/lib64/ld-linux-x86-64.so.2 new file mode 100755 index 00000000..3f5c75a3 Binary files /dev/null and b/tools/testcase-x86_64/lib64/ld-linux-x86-64.so.2 differ diff --git a/tools/testcase-x86_64/libc-bench b/tools/testcase-x86_64/libc-bench new file mode 100755 index 00000000..9423c863 Binary files /dev/null and b/tools/testcase-x86_64/libc-bench differ diff --git a/tools/testcase-x86_64/libc.so b/tools/testcase-x86_64/libc.so new file mode 100755 index 00000000..ac3062ff Binary files /dev/null and b/tools/testcase-x86_64/libc.so differ diff --git a/tools/testcase-x86_64/libctest_testcode.sh b/tools/testcase-x86_64/libctest_testcode.sh new file mode 100755 index 00000000..40b35db5 --- /dev/null +++ b/tools/testcase-x86_64/libctest_testcode.sh @@ -0,0 +1,2 @@ +./run-static.sh +./run-dynamic.sh diff --git a/tools/testcase-x86_64/lmbench_all b/tools/testcase-x86_64/lmbench_all new file mode 100755 index 00000000..3fbc78be Binary files /dev/null and b/tools/testcase-x86_64/lmbench_all differ diff --git a/tools/testcase-x86_64/lmbench_testcode.sh b/tools/testcase-x86_64/lmbench_testcode.sh new file mode 100644 index 00000000..b4096fff --- /dev/null +++ b/tools/testcase-x86_64/lmbench_testcode.sh @@ -0,0 +1,32 @@ +#!/bin/bash +echo latency measurements +lmbench_all lat_syscall -P 1 null +lmbench_all lat_syscall -P 1 read +lmbench_all lat_syscall -P 1 write +busybox mkdir -p /var/tmp +busybox touch /var/tmp/lmbench +lmbench_all lat_syscall -P 1 stat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 fstat /var/tmp/lmbench +lmbench_all lat_syscall -P 1 open /var/tmp/lmbench +lmbench_all lat_select -n 100 -P 1 file +lmbench_all lat_sig -P 1 install +lmbench_all lat_sig -P 1 catch +lmbench_all lat_sig -P 1 prot lat_sig +lmbench_all lat_pipe -P 1 +lmbench_all lat_proc -P 1 fork +lmbench_all lat_proc -P 1 exec +busybox cp hello /tmp +lmbench_all lat_proc -P 1 shell +lmbench_all lmdd label="File /var/tmp/XXX write bandwidth:" of=/var/tmp/XXX move=1m fsync=1 print=3 +lmbench_all lat_pagefault -P 1 /var/tmp/XXX +lmbench_all lat_mmap -P 1 512k /var/tmp/XXX +busybox echo file system latency +lmbench_all lat_fs /var/tmp +busybox echo Bandwidth measurements +lmbench_all bw_pipe -P 1 +lmbench_all bw_file_rd -P 1 512k io_only /var/tmp/XXX +lmbench_all bw_file_rd -P 1 512k open2close /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k mmap_only /var/tmp/XXX +lmbench_all bw_mmap_rd -P 1 512k open2close /var/tmp/XXX +busybox echo context switch overhead +lmbench_all lat_ctx -P 1 -s 32 2 4 8 16 24 32 64 96 diff --git a/tools/testcase-x86_64/long b/tools/testcase-x86_64/long new file mode 100755 index 00000000..e2a2c0a7 Binary files /dev/null and b/tools/testcase-x86_64/long differ diff --git a/tools/testcase-x86_64/looper b/tools/testcase-x86_64/looper new file mode 100755 index 00000000..244af89b Binary files /dev/null and b/tools/testcase-x86_64/looper differ diff --git a/tools/testcase-x86_64/lua b/tools/testcase-x86_64/lua new file mode 100755 index 00000000..c398af98 Binary files /dev/null and b/tools/testcase-x86_64/lua differ diff --git a/tools/testcase-x86_64/lua_testcode.sh b/tools/testcase-x86_64/lua_testcode.sh new file mode 100644 index 00000000..3e8ff55b --- /dev/null +++ b/tools/testcase-x86_64/lua_testcode.sh @@ -0,0 +1,9 @@ +./test.sh date.lua +./test.sh file_io.lua +./test.sh max_min.lua +./test.sh random.lua +./test.sh remove.lua +./test.sh round_num.lua +./test.sh sin30.lua +./test.sh sort.lua +./test.sh strings.lua diff --git a/tools/testcase-x86_64/max_min.lua b/tools/testcase-x86_64/max_min.lua new file mode 100644 index 00000000..7381d617 --- /dev/null +++ b/tools/testcase-x86_64/max_min.lua @@ -0,0 +1,9 @@ + + +if math.max(2, 3, 2, 14, 2, 30, -3) == 30 and math.min(2, 3, 2, 14, 2, 30, -3) == -3 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-x86_64/multi.sh b/tools/testcase-x86_64/multi.sh new file mode 100755 index 00000000..2366bda9 --- /dev/null +++ b/tools/testcase-x86_64/multi.sh @@ -0,0 +1,24 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: multi.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)multi.sh:3.4 -- 5/15/91 19:30:24"; +instance=1 + +while [ $instance -le $1 ]; do + "./tst.sh" "./sort.src" & + instance=$(($instance + 1)) +done +wait + diff --git a/tools/testcase-x86_64/netperf b/tools/testcase-x86_64/netperf new file mode 100755 index 00000000..ccd68c3d Binary files /dev/null and b/tools/testcase-x86_64/netperf differ diff --git a/tools/testcase-x86_64/netperf_testcode.sh b/tools/testcase-x86_64/netperf_testcode.sh new file mode 100644 index 00000000..9a513e10 --- /dev/null +++ b/tools/testcase-x86_64/netperf_testcode.sh @@ -0,0 +1,24 @@ +ip="127.0.0.1" +port=12865 + +run_netperf() { + echo "====== netperf $1 begin ======" + ./netperf -H $ip -p $port -t $1 -l 1 -- $2 + if [ $? == 0 ]; then + ans="success" + else + ans="fail" + fi + echo "====== netperf $1 end: $ans ======" +} + +./netserver -D -L $ip -p $port & +server_pid=$! + +run_netperf UDP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf TCP_STREAM "-s 16k -S 16k -m 1k -M 1k" +run_netperf UDP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_RR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" +run_netperf TCP_CRR "-s 16k -S 16k -m 1k -M 1k -r 64,64 -R 1" + +kill -9 $server_pid diff --git a/tools/testcase-x86_64/netserver b/tools/testcase-x86_64/netserver new file mode 100755 index 00000000..bbeee2dd Binary files /dev/null and b/tools/testcase-x86_64/netserver differ diff --git a/tools/testcase-x86_64/pipe b/tools/testcase-x86_64/pipe new file mode 100755 index 00000000..97f304e0 Binary files /dev/null and b/tools/testcase-x86_64/pipe differ diff --git a/tools/testcase-x86_64/prctl b/tools/testcase-x86_64/prctl new file mode 100755 index 00000000..2696009b Binary files /dev/null and b/tools/testcase-x86_64/prctl differ diff --git a/tools/testcase-x86_64/prctl.c b/tools/testcase-x86_64/prctl.c new file mode 100644 index 00000000..c42786fa --- /dev/null +++ b/tools/testcase-x86_64/prctl.c @@ -0,0 +1,16 @@ +#define _GNU_SOURCE +#include +#include + +int main() { + // 获取进程名称 + char name[16]; + if (prctl(PR_GET_NAME, (unsigned long) name) == -1) { + perror("prctl"); + return 1; + } + + printf("Process name: %s\n", name); + + return 0; +} diff --git a/tools/testcase-x86_64/qjs.static b/tools/testcase-x86_64/qjs.static new file mode 100755 index 00000000..3fe1d188 Binary files /dev/null and b/tools/testcase-x86_64/qjs.static differ diff --git a/tools/testcase-x86_64/qjsc.static b/tools/testcase-x86_64/qjsc.static new file mode 100755 index 00000000..75db2d4e Binary files /dev/null and b/tools/testcase-x86_64/qjsc.static differ diff --git a/tools/testcase-x86_64/random.lua b/tools/testcase-x86_64/random.lua new file mode 100644 index 00000000..f3c27791 --- /dev/null +++ b/tools/testcase-x86_64/random.lua @@ -0,0 +1,13 @@ + + +math.randomseed(os.time()) + +-- num应该大于等于0,小于1 +num = math.random() +if num >= 0 and num < 1 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-x86_64/readlink_parent b/tools/testcase-x86_64/readlink_parent new file mode 100755 index 00000000..078e83e6 Binary files /dev/null and b/tools/testcase-x86_64/readlink_parent differ diff --git a/tools/testcase-x86_64/readlink_parent.c b/tools/testcase-x86_64/readlink_parent.c new file mode 100644 index 00000000..c9ae9ef9 --- /dev/null +++ b/tools/testcase-x86_64/readlink_parent.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 + +int main() { + printf("test readlink(\"/proc/self/exe\",...)\n"); + + // creaate a new process + pid_t pid = fork(); + int wstatus; + if (pid == -1) { + return -1; + } else if (pid == 0) { + // child process + printf("test processs start\n"); + char *const dummy[1] = {NULL}; + execve("./readlink_test", dummy, dummy); + } else { + wait4(pid, &wstatus, WCONTINUED, NULL); + if (WEXITSTATUS(wstatus) == 0) { + printf("Test passed!\n"); + } else { + printf("Test failed.\n"); + } + } + return 0; +} diff --git a/tools/testcase-x86_64/readlink_test b/tools/testcase-x86_64/readlink_test new file mode 100755 index 00000000..0482f1a0 Binary files /dev/null and b/tools/testcase-x86_64/readlink_test differ diff --git a/tools/testcase-x86_64/readlink_test.c b/tools/testcase-x86_64/readlink_test.c new file mode 100644 index 00000000..181e52ce --- /dev/null +++ b/tools/testcase-x86_64/readlink_test.c @@ -0,0 +1,21 @@ +#include +#include + +#define BUFFER_SIZE 1024 + +int main() { + printf("Readlink test:\n"); + + char buffer[BUFFER_SIZE]; + ssize_t result = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); + + if (result != -1) { + buffer[result] = '\0'; + printf("My symbolic link target path: %s\n", buffer); + } else { + perror("error on readlink(\"/proc/self/exe\")"); + return 1; + } + + return 0; +} diff --git a/tools/testcase-x86_64/register b/tools/testcase-x86_64/register new file mode 100755 index 00000000..a4367c90 Binary files /dev/null and b/tools/testcase-x86_64/register differ diff --git a/tools/testcase-x86_64/remove.lua b/tools/testcase-x86_64/remove.lua new file mode 100644 index 00000000..37995ca9 --- /dev/null +++ b/tools/testcase-x86_64/remove.lua @@ -0,0 +1,10 @@ +file = io.open("test.txt", "r") + +if file then + file:close() + if os.remove("test.txt") ~= nil then + return 0 + else + return -1 + end +end diff --git a/tools/testcase-x86_64/round_num.lua b/tools/testcase-x86_64/round_num.lua new file mode 100644 index 00000000..8f60467d --- /dev/null +++ b/tools/testcase-x86_64/round_num.lua @@ -0,0 +1,9 @@ + + +if math.floor(5.6) == 5 and math.ceil(5.6) == 6 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-x86_64/run-dynamic.sh b/tools/testcase-x86_64/run-dynamic.sh new file mode 100755 index 00000000..cc7fb10d --- /dev/null +++ b/tools/testcase-x86_64/run-dynamic.sh @@ -0,0 +1,110 @@ +./runtest.exe -w entry-dynamic.exe argv +./runtest.exe -w entry-dynamic.exe basename +./runtest.exe -w entry-dynamic.exe clocale_mbfuncs +./runtest.exe -w entry-dynamic.exe clock_gettime +./runtest.exe -w entry-dynamic.exe crypt +./runtest.exe -w entry-dynamic.exe dirname +./runtest.exe -w entry-dynamic.exe dlopen +./runtest.exe -w entry-dynamic.exe env +./runtest.exe -w entry-dynamic.exe fdopen +./runtest.exe -w entry-dynamic.exe fnmatch +./runtest.exe -w entry-dynamic.exe fscanf +./runtest.exe -w entry-dynamic.exe fwscanf +./runtest.exe -w entry-dynamic.exe iconv_open +./runtest.exe -w entry-dynamic.exe inet_pton +./runtest.exe -w entry-dynamic.exe mbc +./runtest.exe -w entry-dynamic.exe memstream +./runtest.exe -w entry-dynamic.exe pthread_cancel_points +./runtest.exe -w entry-dynamic.exe pthread_cancel +./runtest.exe -w entry-dynamic.exe pthread_cond +./runtest.exe -w entry-dynamic.exe pthread_tsd +./runtest.exe -w entry-dynamic.exe qsort +./runtest.exe -w entry-dynamic.exe random +./runtest.exe -w entry-dynamic.exe search_hsearch +./runtest.exe -w entry-dynamic.exe search_insque +./runtest.exe -w entry-dynamic.exe search_lsearch +./runtest.exe -w entry-dynamic.exe search_tsearch +./runtest.exe -w entry-dynamic.exe sem_init +./runtest.exe -w entry-dynamic.exe setjmp +./runtest.exe -w entry-dynamic.exe snprintf +./runtest.exe -w entry-dynamic.exe socket +./runtest.exe -w entry-dynamic.exe sscanf +./runtest.exe -w entry-dynamic.exe sscanf_long +./runtest.exe -w entry-dynamic.exe stat +./runtest.exe -w entry-dynamic.exe strftime +./runtest.exe -w entry-dynamic.exe string +./runtest.exe -w entry-dynamic.exe string_memcpy +./runtest.exe -w entry-dynamic.exe string_memmem +./runtest.exe -w entry-dynamic.exe string_memset +./runtest.exe -w entry-dynamic.exe string_strchr +./runtest.exe -w entry-dynamic.exe string_strcspn +./runtest.exe -w entry-dynamic.exe string_strstr +./runtest.exe -w entry-dynamic.exe strptime +./runtest.exe -w entry-dynamic.exe strtod +./runtest.exe -w entry-dynamic.exe strtod_simple +./runtest.exe -w entry-dynamic.exe strtof +./runtest.exe -w entry-dynamic.exe strtol +./runtest.exe -w entry-dynamic.exe strtold +./runtest.exe -w entry-dynamic.exe swprintf +./runtest.exe -w entry-dynamic.exe tgmath +./runtest.exe -w entry-dynamic.exe time +./runtest.exe -w entry-dynamic.exe tls_init +./runtest.exe -w entry-dynamic.exe tls_local_exec +./runtest.exe -w entry-dynamic.exe udiv +./runtest.exe -w entry-dynamic.exe ungetc +./runtest.exe -w entry-dynamic.exe utime +./runtest.exe -w entry-dynamic.exe wcsstr +./runtest.exe -w entry-dynamic.exe wcstol +./runtest.exe -w entry-dynamic.exe daemon_failure +./runtest.exe -w entry-dynamic.exe dn_expand_empty +./runtest.exe -w entry-dynamic.exe dn_expand_ptr_0 +./runtest.exe -w entry-dynamic.exe fflush_exit +./runtest.exe -w entry-dynamic.exe fgets_eof +./runtest.exe -w entry-dynamic.exe fgetwc_buffering +./runtest.exe -w entry-dynamic.exe ftello_unflushed_append +./runtest.exe -w entry-dynamic.exe getpwnam_r_crash +./runtest.exe -w entry-dynamic.exe getpwnam_r_errno +./runtest.exe -w entry-dynamic.exe iconv_roundtrips +./runtest.exe -w entry-dynamic.exe inet_ntop_v4mapped +./runtest.exe -w entry-dynamic.exe inet_pton_empty_last_field +./runtest.exe -w entry-dynamic.exe iswspace_null +./runtest.exe -w entry-dynamic.exe lrand48_signextend +./runtest.exe -w entry-dynamic.exe lseek_large +./runtest.exe -w entry-dynamic.exe malloc_0 +./runtest.exe -w entry-dynamic.exe mbsrtowcs_overflow +./runtest.exe -w entry-dynamic.exe memmem_oob_read +./runtest.exe -w entry-dynamic.exe memmem_oob +./runtest.exe -w entry-dynamic.exe mkdtemp_failure +./runtest.exe -w entry-dynamic.exe mkstemp_failure +./runtest.exe -w entry-dynamic.exe printf_1e9_oob +./runtest.exe -w entry-dynamic.exe printf_fmt_g_round +./runtest.exe -w entry-dynamic.exe printf_fmt_g_zeros +./runtest.exe -w entry-dynamic.exe printf_fmt_n +./runtest.exe -w entry-dynamic.exe pthread_robust_detach +./runtest.exe -w entry-dynamic.exe pthread_cond_smasher +./runtest.exe -w entry-dynamic.exe pthread_condattr_setclock +./runtest.exe -w entry-dynamic.exe pthread_exit_cancel +./runtest.exe -w entry-dynamic.exe pthread_once_deadlock +./runtest.exe -w entry-dynamic.exe pthread_rwlock_ebusy +./runtest.exe -w entry-dynamic.exe putenv_doublefree +./runtest.exe -w entry-dynamic.exe regex_backref_0 +./runtest.exe -w entry-dynamic.exe regex_bracket_icase +./runtest.exe -w entry-dynamic.exe regex_ere_backref +./runtest.exe -w entry-dynamic.exe regex_escaped_high_byte +./runtest.exe -w entry-dynamic.exe regex_negated_range +./runtest.exe -w entry-dynamic.exe regexec_nosub +./runtest.exe -w entry-dynamic.exe rewind_clear_error +./runtest.exe -w entry-dynamic.exe rlimit_open_files +./runtest.exe -w entry-dynamic.exe scanf_bytes_consumed +./runtest.exe -w entry-dynamic.exe scanf_match_literal_eof +./runtest.exe -w entry-dynamic.exe scanf_nullbyte_char +./runtest.exe -w entry-dynamic.exe setvbuf_unget +./runtest.exe -w entry-dynamic.exe sigprocmask_internal +./runtest.exe -w entry-dynamic.exe sscanf_eof +./runtest.exe -w entry-dynamic.exe statvfs +./runtest.exe -w entry-dynamic.exe strverscmp +./runtest.exe -w entry-dynamic.exe syscall_sign_extend +./runtest.exe -w entry-dynamic.exe tls_get_new_dtv +./runtest.exe -w entry-dynamic.exe uselocale_0 +./runtest.exe -w entry-dynamic.exe wcsncpy_read_overflow +./runtest.exe -w entry-dynamic.exe wcsstr_false_negative diff --git a/tools/testcase-x86_64/run-static.sh b/tools/testcase-x86_64/run-static.sh new file mode 100755 index 00000000..346a21c0 --- /dev/null +++ b/tools/testcase-x86_64/run-static.sh @@ -0,0 +1,108 @@ +./runtest.exe -w entry-static.exe argv +./runtest.exe -w entry-static.exe basename +./runtest.exe -w entry-static.exe clocale_mbfuncs +./runtest.exe -w entry-static.exe clock_gettime +./runtest.exe -w entry-static.exe crypt +./runtest.exe -w entry-static.exe dirname +./runtest.exe -w entry-static.exe env +./runtest.exe -w entry-static.exe fdopen +./runtest.exe -w entry-static.exe fnmatch +./runtest.exe -w entry-static.exe fscanf +./runtest.exe -w entry-static.exe fwscanf +./runtest.exe -w entry-static.exe iconv_open +./runtest.exe -w entry-static.exe inet_pton +./runtest.exe -w entry-static.exe mbc +./runtest.exe -w entry-static.exe memstream +./runtest.exe -w entry-static.exe pthread_cancel_points +./runtest.exe -w entry-static.exe pthread_cancel +./runtest.exe -w entry-static.exe pthread_cond +./runtest.exe -w entry-static.exe pthread_tsd +./runtest.exe -w entry-static.exe qsort +./runtest.exe -w entry-static.exe random +./runtest.exe -w entry-static.exe search_hsearch +./runtest.exe -w entry-static.exe search_insque +./runtest.exe -w entry-static.exe search_lsearch +./runtest.exe -w entry-static.exe search_tsearch +./runtest.exe -w entry-static.exe setjmp +./runtest.exe -w entry-static.exe snprintf +./runtest.exe -w entry-static.exe socket +./runtest.exe -w entry-static.exe sscanf +./runtest.exe -w entry-static.exe sscanf_long +./runtest.exe -w entry-static.exe stat +./runtest.exe -w entry-static.exe strftime +./runtest.exe -w entry-static.exe string +./runtest.exe -w entry-static.exe string_memcpy +./runtest.exe -w entry-static.exe string_memmem +./runtest.exe -w entry-static.exe string_memset +./runtest.exe -w entry-static.exe string_strchr +./runtest.exe -w entry-static.exe string_strcspn +./runtest.exe -w entry-static.exe string_strstr +./runtest.exe -w entry-static.exe strptime +./runtest.exe -w entry-static.exe strtod +./runtest.exe -w entry-static.exe strtod_simple +./runtest.exe -w entry-static.exe strtof +./runtest.exe -w entry-static.exe strtol +./runtest.exe -w entry-static.exe strtold +./runtest.exe -w entry-static.exe swprintf +./runtest.exe -w entry-static.exe tgmath +./runtest.exe -w entry-static.exe time +./runtest.exe -w entry-static.exe tls_align +./runtest.exe -w entry-static.exe udiv +./runtest.exe -w entry-static.exe ungetc +./runtest.exe -w entry-static.exe utime +./runtest.exe -w entry-static.exe wcsstr +./runtest.exe -w entry-static.exe wcstol +./runtest.exe -w entry-static.exe pleval +./runtest.exe -w entry-static.exe daemon_failure +./runtest.exe -w entry-static.exe dn_expand_empty +./runtest.exe -w entry-static.exe dn_expand_ptr_0 +./runtest.exe -w entry-static.exe fflush_exit +./runtest.exe -w entry-static.exe fgets_eof +./runtest.exe -w entry-static.exe fgetwc_buffering +./runtest.exe -w entry-static.exe ftello_unflushed_append +./runtest.exe -w entry-static.exe getpwnam_r_crash +./runtest.exe -w entry-static.exe getpwnam_r_errno +./runtest.exe -w entry-static.exe iconv_roundtrips +./runtest.exe -w entry-static.exe inet_ntop_v4mapped +./runtest.exe -w entry-static.exe inet_pton_empty_last_field +./runtest.exe -w entry-static.exe iswspace_null +./runtest.exe -w entry-static.exe lrand48_signextend +./runtest.exe -w entry-static.exe lseek_large +./runtest.exe -w entry-static.exe malloc_0 +./runtest.exe -w entry-static.exe mbsrtowcs_overflow +./runtest.exe -w entry-static.exe memmem_oob_read +./runtest.exe -w entry-static.exe memmem_oob +./runtest.exe -w entry-static.exe mkdtemp_failure +./runtest.exe -w entry-static.exe mkstemp_failure +./runtest.exe -w entry-static.exe printf_1e9_oob +./runtest.exe -w entry-static.exe printf_fmt_g_round +./runtest.exe -w entry-static.exe printf_fmt_g_zeros +./runtest.exe -w entry-static.exe printf_fmt_n +./runtest.exe -w entry-static.exe pthread_robust_detach +./runtest.exe -w entry-static.exe pthread_cancel_sem_wait +./runtest.exe -w entry-static.exe pthread_cond_smasher +./runtest.exe -w entry-static.exe pthread_condattr_setclock +./runtest.exe -w entry-static.exe pthread_exit_cancel +./runtest.exe -w entry-static.exe pthread_once_deadlock +./runtest.exe -w entry-static.exe pthread_rwlock_ebusy +./runtest.exe -w entry-static.exe putenv_doublefree +./runtest.exe -w entry-static.exe regex_backref_0 +./runtest.exe -w entry-static.exe regex_bracket_icase +./runtest.exe -w entry-static.exe regex_ere_backref +./runtest.exe -w entry-static.exe regex_escaped_high_byte +./runtest.exe -w entry-static.exe regex_negated_range +./runtest.exe -w entry-static.exe regexec_nosub +./runtest.exe -w entry-static.exe rewind_clear_error +./runtest.exe -w entry-static.exe rlimit_open_files +./runtest.exe -w entry-static.exe scanf_bytes_consumed +./runtest.exe -w entry-static.exe scanf_match_literal_eof +./runtest.exe -w entry-static.exe scanf_nullbyte_char +./runtest.exe -w entry-static.exe setvbuf_unget +./runtest.exe -w entry-static.exe sigprocmask_internal +./runtest.exe -w entry-static.exe sscanf_eof +./runtest.exe -w entry-static.exe statvfs +./runtest.exe -w entry-static.exe strverscmp +./runtest.exe -w entry-static.exe syscall_sign_extend +./runtest.exe -w entry-static.exe uselocale_0 +./runtest.exe -w entry-static.exe wcsncpy_read_overflow +./runtest.exe -w entry-static.exe wcsstr_false_negative diff --git a/tools/testcase-x86_64/runtest.exe b/tools/testcase-x86_64/runtest.exe new file mode 100755 index 00000000..068f17cb Binary files /dev/null and b/tools/testcase-x86_64/runtest.exe differ diff --git a/tools/testcase-x86_64/short b/tools/testcase-x86_64/short new file mode 100755 index 00000000..266473c4 Binary files /dev/null and b/tools/testcase-x86_64/short differ diff --git a/tools/testcase-x86_64/sin30.lua b/tools/testcase-x86_64/sin30.lua new file mode 100644 index 00000000..bcc1e989 --- /dev/null +++ b/tools/testcase-x86_64/sin30.lua @@ -0,0 +1,9 @@ + + +if math.sin(math.rad(30)) == 0.5 then + return 0 +else + return -1 +end + + diff --git a/tools/testcase-x86_64/sort.lua b/tools/testcase-x86_64/sort.lua new file mode 100644 index 00000000..942d0395 --- /dev/null +++ b/tools/testcase-x86_64/sort.lua @@ -0,0 +1,13 @@ + + +local tb = {20, 10, 2, 3, 4, 89, 20, 33, 2, 3} + +local rst = {2, 2, 3, 3, 4, 10, 20, 20, 33, 89} + +table.sort(tb) + +if tb == rst then + return 0 +else + return -1 +end diff --git a/tools/testcase-x86_64/sort.src b/tools/testcase-x86_64/sort.src new file mode 100644 index 00000000..6a72fa84 --- /dev/null +++ b/tools/testcase-x86_64/sort.src @@ -0,0 +1,362 @@ +version="1.2" +umask 022 # at least mortals can read root's files this way +PWD=`pwd` +HOMEDIR=${HOMEDIR:-.} +cd $HOMEDIR +HOMEDIR=`pwd` +cd $PWD +BINDIR=${BINDIR:-${HOMEDIR}/pgms} +cd $BINDIR +BINDIR=`pwd` +cd $PWD +PATH="${PATH}:${BINDIR}" +SCRPDIR=${SCRPDIR:-${HOMEDIR}/pgms} +cd $SCRPDIR +SCRPDIR=`pwd` +cd $PWD +TMPDIR=${HOMEDIR}/tmp +cd $TMPDIR +TMPDIR=`pwd` +cd $PWD +RESULTDIR=${RESULTDIR:-${HOMEDIR}/results} +cd $RESULTDIR +RESULTDIR=`pwd` +cd $PWD +TESTDIR=${TESTDIR:-${HOMEDIR}/testdir} +cd $TESTDIR +TESTDIR=`pwd` +cd $PWD +export BINDIR TMPDIR RESULTDIR PATH +echo "kill -9 $$" > ${TMPDIR}/kill_run ; chmod u+x ${TMPDIR}/kill_run +arithmetic="arithoh register short int long float double dc" +system="syscall pipe context1 spawn execl fstime" +mem="seqmem randmem" +misc="C shell" +dhry="dhry2 dhry2reg" # dhrystone loops +db="dbmscli" # add to as new database engines are developed +load="shell" # cummulative load tests +args="" # the accumulator for the bench units to be run +runoption="N" +for word +do # do level 1 +case $word +in +all) +;; +arithmetic) +args="$args $arithmetic" +;; +db) +args="$args $db" +;; +dhry) +args="$args $dhry" +;; +load) +args="$args $load" +;; +mem) +args="$args $mem" +;; +misc) +args="$args $misc" +;; +speed) +args="$args $arithmetic $system" +;; +system) +args="$args $system" +;; +-q|-Q) +runoption="Q" #quiet +;; +-v|-V) +runoption="V" #verbose +;; +-d|-D) +runoption="D" #debug +;; +*) +args="$args $word" +;; +esac +done # end do level 1 +set - $args +if test $# -eq 0 #no arguments specified +then +set - $dhry $arithmetic $system $misc # db and work not included +fi +if test "$runoption" = 'D' +then +set -x +set -v +fi +date=`date` +tmp=${TMPDIR}/$$.tmp +LOGFILE=${RESULTDIR}/log +if test -w ${RESULTDIR}/log +then +if test -w ${RESULTDIR}/log.accum +then +cat ${RESULTDIR}/log >> ${RESULTDIR}/log.accum +rm ${RESULTDIR}/log +else +mv ${RESULTDIR}/log ${RESULTDIR}/log.accum +fi +echo "Start Benchmark Run (BYTE Version $version)" >>$LOGFILE +echo " $date (long iterations $iter times)" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +uname -a >>$LOGFILE +iter=${iterations-6} +if test $iter -eq 6 +then +longloop="1 2 3 4 5 6" +shortloop="1 2 3" +else # generate list of loop numbers +short=`expr \( $iter + 1 \) / 2` +longloop="" +shortloop="" +while test $iter -gt 0 +do # do level 1 +longloop="$iter $longloop" +if test $iter -le $short +then +shortloop="$iter $shortloop" +fi +iter=`expr $iter - 1` +done # end do level 1 +fi #loop list genration +for bench # line argument processing +do # do level 1 +# set some default values +prog=${BINDIR}/$bench # the bench name is default program +need=$prog # we need the at least the program +paramlist="#" # a dummy parameter to make anything run +testdir="${TESTDIR}" # the directory in which to run the test +prepcmd="" # preparation command or script +parammsg="" +repeat="$longloop" +stdout="$LOGFILE" +stdin="" +cleanopt="-t $tmp" +bgnumber="" +trap "${SCRPDIR}/cleanup -l $LOGFILE -a; exit" 1 2 3 15 +if [ $runoption != 'Q' ] +then +echo "$bench: \c" +fi +echo "" >>$LOGFILE +###################### select the bench specific values ########## +case $bench +in +dhry2) +options=${dhryloops-10000} +logmsg="Dhrystone 2 without register variables" +cleanopt="-d $tmp" +;; +dhry2reg) +options=${dhryloops-10000} +logmsg="Dhrystone 2 using register variables" +cleanopt="-d $tmp" +;; +arithoh|register|short|int|long|float|double) +options=${arithloop-10000} +logmsg="Arithmetic Test (type = $bench): $options Iterations" +;; +dc) need=dc.dat +prog=dc +options="" +stdin=dc.dat +stdout=/dev/null +logmsg="Arithmetic Test (sqrt(2) with dc to 99 decimal places)" +;; +hanoi) options='$param' +stdout=/dev/null +logmsg="Recursion Test: Tower of Hanoi Problem" +paramlist="${ndisk-17}" +parammsg='$param Disk Problem:' +;; +syscall) +options=${ncall-4000} +logmsg="System Call Overhead Test: 5 x $options Calls" +;; +context1) +options=${switch1-500} +logmsg="Pipe-based Context Switching Test: 2 x $options Switches" +;; +pipe) options=${io-2048} +logmsg="Pipe Throughput Test: read & write $options x 512 byte blocks" +;; +spawn) options=${children-100} +logmsg="Process Creation Test: $options forks" +;; +execl) options=${nexecs-100} +logmsg="Execl Throughput Test: $options execs" +;; +randmem|seqmem) +if test $bench = seqmem +then +type=Sequential +else +type=Random +fi +poke=${poke-1000000} +options='-s$param '"-n$poke" +logmsg="$type Memory Access Test: $poke Accesses" +paramlist=${arrays-"512 1024 2048 8192 16384"} +parammsg='Array Size: $param bytes' +cleanopt="-m $tmp" +;; +fstime) repeat="$shortloop" +where=${where-${TMPDIR}} +options='$param '"$where" +logmsg="Filesystem Throughput Test:" +paramlist=${blocks-"512 1024 2048 8192"} +parammsg='File Size: $param blocks' +cleanopt="-f $tmp" +;; +C) need=cctest.c +prog=cc +options='$param' +stdout=/dev/null +repeat="$shortloop" +logmsg="C Compiler Test:" +paramlist="cctest.c" +parammsg='cc $param' +rm -f a.out +;; +dbmscli) +repeat="$shortloop" +need="db.dat" +prepcmd='${BINDIR}/dbprep ${testdir}/db.dat 10000' +paramlist=${clients-"1 2 4 8"} +parammsg='$param client processes. (filesize `cat ${testdir}/db.dat|wc -c` bytes)' +logmsg="Client/Server Database Engine:" +options='${testdir}/db.dat $param 0 1000' # $param clients; +# 0 sleep; 1000 iterations +;; +shell) +prog="multi.sh" +repeat="$shortloop" +logmsg="Bourne shell script and Unix utilities" +paramlist=${background-"1 2 4 8"} +parammsg='$param concurrent background processes' +bgnumber='$param' +testdir="shelldir" +;; +*) ${BINDIR}/cleanup -l $LOGFILE -r "run: unknown benchmark \"$bench\"" -a +exit 1 +;; +esac +echo "$logmsg" >>$LOGFILE +for param in $paramlist +do # level 2 +param=`echo $param | sed 's/_/ /g'` # be sure that spaces are used +# underscore can couple params +if [ "$runoption" != "Q" ] +then +echo "\n [$param] -\c" # generate message to user +fi +eval msg='"'$parammsg'"' # the eval is used to +if test "$msg" # evaluate any embedded +then # variables in the parammsg +echo "" >>$LOGFILE +echo "$msg" >>$LOGFILE +fi +eval opt='"'$options'"' # evaluate any vars in options +eval prep='"'$prepcmd'"' # evaluate any prep command +eval bg='"'$bgnumber'"' # evaluate bgnumber string +rm -f $tmp # remove any tmp files +# if the test requires mulitple concurrent processes, +# prepare the background process string (bgstr) +# this is just a string of "+"s that will provides a +# parameter count for a "for" loop +bgstr="" +if test "$bg" != "" +then +count=`expr "$bg"` +while test $count -gt 0 +do +bgstr="+ $bgstr" +count=`expr $count - 1` +done +fi +# +for i in $repeat # loop for the specified number +do # do depth 3 +if [ "$runoption" != 'D' ] # level 1 +then +# regular Run - set logfile to go on signal +trap "${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -a; exit" 1 2 3 15 +else +trap "exit" 1 2 3 15 +fi #end level 1 +if [ "$runoption" != 'Q' ] +then +echo " $i\c" # display repeat number +fi +pwd=`pwd` # remember where we are +cd $testdir # move to the test directory +if [ "$runoption" = "V" ] +then +echo +echo "BENCH COMMAND TO BE EXECUTED:" +echo "$prog $opt" +fi +# execute any prepratory command string +if [ -n "$prep" ] +then +$prep >>$stdout +fi +############ THE BENCH IS TIMED ############## +if test "$stdin" = "" +then # without redirected stdin +time $prog $opt $bgstr 2>>$tmp >>$stdout +else # with redirected stdin +time $prog $opt $bgstr <$stdin 2>>$tmp >>$stdout +fi +time $benchcmd +############################################### +cd $pwd # move back home +status=$? # save the result code +if test $status != 0 # must have been an error +then +if test -f $tmp # is there an error file ? +then +cp $tmp ${TMPDIR}/save.$bench.$param +${SCRPDIR}/cleanup -l $LOGFILE -i $i $cleanopt -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +else +${SCRPDIR}/cleanup -l $LOGFILE -r \ +"run: bench=$bench param=$param fatalstatus=$status" -a +fi +exit # leave the script if there are errors +fi # end level 1 +done # end do depth 3 - repeat of bench +if [ "$runoption" != 'D' ] +then +${SCRPDIR}/cleanup -l $LOGFILE $cleanopt # finalize this bench +# with these options +# & calculate results +fi +done # end do depth 2 - end of all options for this bench +########### some specific cleanup routines ############## +case $bench +in +C) +rm -f cctest.o a.out +;; +esac +if [ "$runoption" != 'Q' ] +then +echo "" +fi +done # end do level 1 - all benchmarks requested +echo "" >>$LOGFILE +echo " " `who | wc -l` "interactive users." >>$LOGFILE +echo "End Benchmark Run ($date) ...." >>$LOGFILE +if [ "$runoption" != 'Q' ] +then +pg $LOGFILE +fi +exit diff --git a/tools/testcase-x86_64/spawn b/tools/testcase-x86_64/spawn new file mode 100755 index 00000000..24811148 Binary files /dev/null and b/tools/testcase-x86_64/spawn differ diff --git a/tools/testcase-x86_64/strings.lua b/tools/testcase-x86_64/strings.lua new file mode 100644 index 00000000..2a1b1579 --- /dev/null +++ b/tools/testcase-x86_64/strings.lua @@ -0,0 +1,35 @@ + + +local str = "Jelly Think" + +result = 0 + +-- string.len可以获得字符串的长度 + +if string.len(str) ~= 11 then + result = -1 +end + +-- string.rep返回字符串重复n次的结果 + +str = "ab" + +if string.rep(str, 2) ~= "abab" then + result = -1 +end + +-- string.lower将字符串小写变成大写形式,并返回一个改变以后的副本 + +str = "Jelly Think" + +if string.lower(str) ~= "jelly think" then + result = -1 +end + +-- string.upper将字符串大写变成小写形式,并返回一个改变以后的副本 + +if string.upper(str) == "JELLY THINK" then + result = -1 +end + +return result diff --git a/tools/testcase-x86_64/syscall b/tools/testcase-x86_64/syscall new file mode 100755 index 00000000..b68472fe Binary files /dev/null and b/tools/testcase-x86_64/syscall differ diff --git a/tools/testcase-x86_64/test-vfork-exec-x86_64 b/tools/testcase-x86_64/test-vfork-exec-x86_64 new file mode 100644 index 00000000..e5828049 Binary files /dev/null and b/tools/testcase-x86_64/test-vfork-exec-x86_64 differ diff --git a/tools/testcase-x86_64/test-vfork-exec.c b/tools/testcase-x86_64/test-vfork-exec.c new file mode 100644 index 00000000..1c080b07 --- /dev/null +++ b/tools/testcase-x86_64/test-vfork-exec.c @@ -0,0 +1,59 @@ +// Originally From: https://elixir.bootlin.com/glibc/glibc-2.38/source/posix/test-vfork.c +// Made it musl compatible + +#include +#include +#include +// #include +#include +#include + +// void __attribute_noinline__ noop (void); + +#define NR 2 /* Exit code of the child. */ + +/* + The successful output is + Before vfork + Child print something (child). + After vfork (parent) +*/ +int +main (void) +{ + pid_t pid; + int status; + char* execv_str[] = {"echo", "Child exec done, quitting", NULL}; + + printf ("Before vfork\n"); + fflush (stdout); + pid = vfork (); + if (pid == 0) + { + /* This will clobber the return pc from vfork in the parent on + machines where it is stored on the stack, if vfork wasn't + implemented correctly, */ + // noop (); + printf("Child spawn, blocking parent\n"); + sleep(1); + execv("/busybox", execv_str); + printf("Error: this line is not supposed to be printed\n"); + } + else if (pid < 0) { + // error (1, errno, "vfork"); + printf("vfork error: %d\n", errno); + exit(errno); + } + printf ("Executed by execv, child stop blocking\n"); + if (waitpid (0, &status, 0) != pid + || !WIFEXITED (status) || WEXITSTATUS (status) != NR) + exit (1); + + return 0; +} + +void +noop (void) +{ +} + diff --git a/tools/testcase-x86_64/test-vfork-exit-x86_64 b/tools/testcase-x86_64/test-vfork-exit-x86_64 new file mode 100644 index 00000000..79c0dc8f Binary files /dev/null and b/tools/testcase-x86_64/test-vfork-exit-x86_64 differ diff --git a/tools/testcase-x86_64/test-vfork-exit.c b/tools/testcase-x86_64/test-vfork-exit.c new file mode 100644 index 00000000..cea87320 --- /dev/null +++ b/tools/testcase-x86_64/test-vfork-exit.c @@ -0,0 +1,57 @@ +// Originally From: https://elixir.bootlin.com/glibc/glibc-2.38/source/posix/test-vfork.c +// Made it musl compatible + +#include +#include +#include +// #include +#include +#include + +// void __attribute_noinline__ noop (void); + +#define NR 2 /* Exit code of the child. */ + +/* + The successful output is + Before vfork + Child print something (child). + After vfork (parent) +*/ +int +main (void) +{ + pid_t pid; + int status; + + printf ("Before vfork\n"); + fflush (stdout); + pid = vfork (); + if (pid == 0) + { + /* This will clobber the return pc from vfork in the parent on + machines where it is stored on the stack, if vfork wasn't + implemented correctly, */ + // noop (); + sleep(1); + printf("Child print something (child).\n"); + _exit (NR); + } + else if (pid < 0) { + // error (1, errno, "vfork"); + printf("vfork error: %d\n", errno); + exit(errno); + } + printf ("After vfork (parent)\n"); + if (waitpid (0, &status, 0) != pid + || !WIFEXITED (status) || WEXITSTATUS (status) != NR) + exit (1); + + return 0; +} + +void +noop (void) +{ +} + diff --git a/tools/testcase-x86_64/test.js b/tools/testcase-x86_64/test.js new file mode 100644 index 00000000..c5004688 --- /dev/null +++ b/tools/testcase-x86_64/test.js @@ -0,0 +1 @@ +console.log("Hello quickjs"); diff --git a/tools/testcase-x86_64/test.sh b/tools/testcase-x86_64/test.sh new file mode 100755 index 00000000..7184e1a7 --- /dev/null +++ b/tools/testcase-x86_64/test.sh @@ -0,0 +1,8 @@ +#!/bin/busybox sh + +./lua $1 +if [ $? == 0 ]; then + echo "testcase lua $1 success" +else + echo "testcase lua $1 fail" +fi diff --git a/tools/testcase-x86_64/test_all.sh b/tools/testcase-x86_64/test_all.sh new file mode 100644 index 00000000..1c4b1cf6 --- /dev/null +++ b/tools/testcase-x86_64/test_all.sh @@ -0,0 +1,22 @@ +busybox echo "run time-test" +./time-test +busybox echo "run busybox_testcode.sh" +./busybox_testcode.sh +busybox echo "run iozone_testcode.sh" +./iozone_testcode.sh +busybox echo "run libctest_testcode.sh" +./libctest_testcode.sh +busybox echo "run libc-bench" +./libc-bench +busybox echo "run lmbench_testcode.sh" +./lmbench_testcode.sh +busybox echo "run lua_testcode.sh" +./lua_testcode.sh +busybox echo "run unixbench_testcode.sh" +./unixbench_testcode.sh +busybox echo "run netperf_testcode.sh" +./netperf_testcode.sh +busybox echo "run iperf_testcode.sh" +./iperf_testcode.sh +busybox echo "run cyclic_testcode.sh" +./cyclic_testcode.sh \ No newline at end of file diff --git a/tools/testcase-x86_64/time-test b/tools/testcase-x86_64/time-test new file mode 100755 index 00000000..30a5ca52 Binary files /dev/null and b/tools/testcase-x86_64/time-test differ diff --git a/tools/testcase-x86_64/tls_align_dso.so b/tools/testcase-x86_64/tls_align_dso.so new file mode 100755 index 00000000..e9b1ca97 Binary files /dev/null and b/tools/testcase-x86_64/tls_align_dso.so differ diff --git a/tools/testcase-x86_64/tls_get_new-dtv_dso.so b/tools/testcase-x86_64/tls_get_new-dtv_dso.so new file mode 100755 index 00000000..62309840 Binary files /dev/null and b/tools/testcase-x86_64/tls_get_new-dtv_dso.so differ diff --git a/tools/testcase-x86_64/tls_init_dso.so b/tools/testcase-x86_64/tls_init_dso.so new file mode 100755 index 00000000..03aba603 Binary files /dev/null and b/tools/testcase-x86_64/tls_init_dso.so differ diff --git a/tools/testcase-x86_64/tst.sh b/tools/testcase-x86_64/tst.sh new file mode 100755 index 00000000..4b2b025b --- /dev/null +++ b/tools/testcase-x86_64/tst.sh @@ -0,0 +1,20 @@ +#! /bin/sh +############################################################################### +# The BYTE UNIX Benchmarks - Release 3 +# Module: tst.sh SID: 3.4 5/15/91 19:30:24 +# +############################################################################### +# Bug reports, patches, comments, suggestions should be sent to: +# +# Ben Smith or Rick Grehan at BYTE Magazine +# ben@bytepb.UUCP rick_g@bytepb.UUCP +# +############################################################################### +# Modification Log: +# +############################################################################### +ID="@(#)tst.sh:3.4 -- 5/15/91 19:30:24"; +./busybox sort > sort.$$ < $1 +./busybox od sort.$$ | ./busybox sort -n -k 1 > od.$$ +./busybox grep the sort.$$ | ./busybox tee grep.$$ | ./busybox wc > wc.$$ +./busybox rm sort.$$ grep.$$ od.$$ wc.$$ diff --git a/tools/testcase-x86_64/unixbench_testcode.sh b/tools/testcase-x86_64/unixbench_testcode.sh new file mode 100755 index 00000000..c127ad94 --- /dev/null +++ b/tools/testcase-x86_64/unixbench_testcode.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +#export CC=gcc + +./dhry2reg 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DHRY2 test(lps): "$0}' +./whetstone-double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+.[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+.[[:digit:]]\+" | ./busybox awk '{print "Unixbench WHETSTONE test(MFLOPS): "$0}' +./syscall 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SYSCALL test(lps): "$0}' +./context1 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox tail -n1 | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench CONTEXT test(lps): "$0}' +./pipe 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench PIPE test(lps): "$0}' +./spawn 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SPAWN test(lps): "$0}' +UB_BINDIR=./ ./execl 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXECL test(lps): "$0}' + +#./fstime +./fstime -w -t 20 -b 256 -m 500 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_SMALL test(KBps): "$0}' +./fstime -r -t 20 -b 256 -m 500 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_SMALL test(KBps): "$0}' +./fstime -c -t 20 -b 256 -m 500 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_SMALL test(KBps): "$0}' + +./fstime -w -t 20 -b 1024 -m 2000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_MIDDLE test(KBps): "$0}' +./fstime -r -t 20 -b 1024 -m 2000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_MIDDLE test(KBps): "$0}' +./fstime -c -t 20 -b 1024 -m 2000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_MIDDLE test(KBps): "$0}' + +./fstime -w -t 20 -b 4096 -m 8000 | ./busybox grep -o "WRITE COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_WRITE_BIG test(KBps): "$0}' +./fstime -r -t 20 -b 4096 -m 8000 | ./busybox grep -o "READ COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_READ_BIG test(KBps): "$0}' +./fstime -c -t 20 -b 4096 -m 8000 | ./busybox grep -o "COPY COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FS_COPY_BIG test(KBps): "$0}' + + +./looper 20 ./multi.sh 1 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL1 test(lpm): "$0}' +./looper 20 ./multi.sh 8 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL8 test(lpm): "$0}' +./looper 20 ./multi.sh 16 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHELL16 test(lpm): "$0}' +#./looper 30 dc < ../testdir/dc.dat 2>&1 + +./arithoh 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench ARITHOH test(lps): "$0}' +./short 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench SHORT test(lps): "$0}' +./int 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench INT test(lps): "$0}' +./long 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench LONG test(lps): "$0}' +./float 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench FLOAT test(lps): "$0}' +./double 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench DOUBLE test(lps): "$0}' +./hanoi 10 | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench HANOI test(lps): "$0}' +./syscall 10 exec | ./busybox grep -o "COUNT|[[:digit:]]\+|" | ./busybox grep -o "[[:digit:]]\+" | ./busybox awk '{print "Unixbench EXEC test(lps): "$0}' diff --git a/tools/testcase-x86_64/whetstone-double b/tools/testcase-x86_64/whetstone-double new file mode 100755 index 00000000..4ef5aa4c Binary files /dev/null and b/tools/testcase-x86_64/whetstone-double differ diff --git a/tools/vgabios-virtio.bin b/tools/vgabios-virtio.bin new file mode 100644 index 00000000..f4178f70 Binary files /dev/null and b/tools/vgabios-virtio.bin differ