Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"examples/loopback",
"examples/miotcp",
"examples/mioudp",
"examples/nvme-test",
"examples/polling",
"examples/rftrace-example",
"examples/stdin",
Expand Down
5 changes: 5 additions & 0 deletions examples/nvme-test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
hermit-loader-x86_64
hermit-loader-aarch64
hermit-loader-riscv64
opensbi*
nvme.img
11 changes: 11 additions & 0 deletions examples/nvme-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "nvme-test"
authors = ["Valentin Kunisch <v.qnish@protonmail.com>"]
edition = "2024"

[target.'cfg(target_os = "hermit")'.dependencies]
hermit = { path = "../../hermit", default-features = false, features = ["nvme"] }

[dependencies]
rand = "0.9.2"
vroom = { git = "https://github.com/valopok/vroom", branch = "main", default-features = false }
73 changes: 73 additions & 0 deletions examples/nvme-test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.PHONY: run-x86_64
run-x86_64: build-x86_64 disk-image
# https://github.com/hermit-os/loader?tab=readme-ov-file#x86-64
qemu-system-x86_64 \
-cpu qemu64,apic,fsgsbase,fxsr,rdrand,rdtscp,xsave,xsaveopt \
-smp 1 \
-m 128M \
-device isa-debug-exit,iobase=0xf4,iosize=0x04 \
-display none \
-serial stdio \
-kernel hermit-loader-x86_64 \
-initrd ../../target/x86_64-unknown-hermit/release/nvme-test \
-drive file=nvme.img,format=raw,if=none,id=nvm \
-device nvme,serial=deadbeef,drive=nvm

.PHONY: run-aarch64
run-aarch64: build-aarch64 disk-image
# https://github.com/hermit-os/loader?tab=readme-ov-file#aarch64
qemu-system-aarch64 \
-machine virt,gic-version=3 \
-cpu cortex-a76 \
-smp 1 \
-m 512M \
-semihosting \
-display none \
-serial stdio \
-kernel hermit-loader-aarch64 \
-device guest-loader,addr=0x48000000,initrd=../../target/aarch64-unknown-hermit/release/nvme-test \
-drive file=nvme.img,format=raw,if=none,id=nvm \
-device nvme,serial=deadbeef,drive=nvm

# .PHONY: run-riscv64
# run-riscv64: build-riscv64 disk-image
# # https://github.com/hermit-os/loader?tab=readme-ov-file#64-bit-risc-v
# qemu-system-riscv64 \
# -machine virt \
# -cpu rv64 \
# -smp 1 \
# -m 128M \
# -display none \
# -serial stdio \
# -bios opensbi/share/opensbi/lp64/generic/firmware/fw_jump.bin \
# -kernel hermit-loader-riscv64 \
# -initrd ../../target/riscv64gc-unknown-hermit/release/nvme-test \
# -drive file=nvme.img,format=raw,if=none,id=nvm \
# -device nvme,serial=deadbeef,drive=nvm

.PHONY: build-x86_64
build-x86_64:
HERMIT_LOG_LEVEL_FILTER=ERROR \
cargo build -Z build-std=std,core,alloc,panic_abort \
--target x86_64-unknown-hermit --release

.PHONY: build-aarch64
build-aarch64:
HERMIT_LOG_LEVEL_FILTER=ERROR \
cargo build -Z build-std=std,core,alloc,panic_abort \
--target aarch64-unknown-hermit --release

# .PHONY: build-riscv64
# build-riscv64:
# HERMIT_LOG_LEVEL_FILTER=ERROR \
# cargo build -Z build-std=std,core,alloc,panic_abort \
# --target riscv64gc-unknown-hermit

.PHONY: disk-image
disk-image:
qemu-img create nvme.img 4M

.PHONY: clean
clean:
cargo clean
rm -f nvme.img
19 changes: 19 additions & 0 deletions examples/nvme-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# An example program to test the NVMe driver

> Note: PCI devices are not yet implemented for `riscv64`.

Complete following steps to run the test with QEMU:

- Install [QEMU](https://www.qemu.org) to get the commands
`qemu-system-x86_64`, `qemu-system-aarch64`.

- Download the [hermit-loaders](https://github.com/hermit-os/loader/releases) for
`x86_64`, `aarch64` and place them into this nvme-test directory.

> `riscv64` only: download [OpenSBI](https://github.com/riscv-software-src/opensbi/releases),
rename the directory to `opensbi` and place it into this nvme-test directory.

- Execute `make run-x86_64` (default) or `make run-aarch64` to run the program.

- Cleanup files with `make clean` afterwards.

71 changes: 71 additions & 0 deletions examples/nvme-test/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#[cfg(target_os = "hermit")]
use hermit as _;

mod syscalls;
mod tests;
use syscalls::*;
use tests::run_tests;

fn main() {
println!("Hello, NVMe!");
// CAREFUL: this example writes to the NVMe drive
// match example() {
// Err(error) => eprintln!("{error:?}"),
// Ok(()) => println!("Success!"),
// }
run_tests();
}

#[allow(dead_code)]
fn example() -> Result<(), SysNvmeError> {
let namespace_ids = namespace_ids()?;
println!("Namespace IDs: {namespace_ids:?}.");

let namespace_id = namespace_ids[0];
let namespace = namespace(&namespace_id)?;
println!("Namespace: {namespace:?}");
println!(
"Total namespace size: {}",
namespace.blocks * namespace.block_size
);

let maximum_transfer_size = maximum_transfer_size()?;
println!("Maximum transfer size: {maximum_transfer_size}.");

let maximum_number_of_io_queue_pairs = maximum_number_of_io_queue_pairs()?;
println!("Maximum number of I/O queue pairs: {maximum_number_of_io_queue_pairs}.");

let maximum_queue_entries_supported = maximum_queue_entries_supported()?;
println!("Maximum queue entries supported: {maximum_queue_entries_supported}.");

let io_queue_pair_id = create_io_queue_pair(&namespace_id, maximum_queue_entries_supported)?;
println!(
"Created IO queue pair with ID {} and {} queue entries for namespace {}.",
io_queue_pair_id.0, maximum_queue_entries_supported, namespace_id.0
);

let length = 16;
let mut buffer_1 = allocate_buffer(&io_queue_pair_id, length)?;
for i in 0..length {
buffer_1[i] = i as u8;
}

let logical_block_address = 0;
write_to_io_queue_pair(&io_queue_pair_id, &buffer_1, logical_block_address)?;
println!("Wrote to IO queue pair with ID {io_queue_pair_id:?}.");

let mut buffer_2 = allocate_buffer(&io_queue_pair_id, length)?;
read_from_io_queue_pair(&io_queue_pair_id, &mut buffer_2, logical_block_address)?;
println!("Read from IO queue pair with ID {io_queue_pair_id:?}.");

println!("buffer_1: {:?}", &buffer_1[0..length]);
println!("buffer_2: {:?}", &buffer_2[0..length]);

deallocate_buffer(&io_queue_pair_id, buffer_1)?;
deallocate_buffer(&io_queue_pair_id, buffer_2)?;
println!("Deallocated buffers.");

delete_io_queue_pair(io_queue_pair_id)?;
println!("Deleted IO queue pair.");
Ok(())
}
Loading