Эх сурвалжийг харах

add a buggy riscv example

Runji Wang 5 жил өмнө
parent
commit
1fc701f140

+ 12 - 0
examples/riscv/.cargo/config

@@ -0,0 +1,12 @@
+[build]
+target = "riscv64imac-unknown-none-elf"
+
+[target.riscv32imac-unknown-none-elf]
+rustflags = [
+    "-C", "link-arg=-Tlinker32.ld",
+]
+
+[target.riscv64imac-unknown-none-elf]
+rustflags = [
+    "-C", "link-arg=-Tlinker64.ld",
+]

+ 2 - 0
examples/riscv/.gitignore

@@ -0,0 +1,2 @@
+/target
+Cargo.lock

+ 14 - 0
examples/riscv/Cargo.toml

@@ -0,0 +1,14 @@
+[package]
+name = "riscv"
+version = "0.1.0"
+authors = ["Runji Wang <wangrunji0408@163.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+log = "0.4"
+riscv = "0.5"
+opensbi-rt = { git = "https://github.com/rcore-os/opensbi-rt.git", rev = "38399b6" }
+device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2fa8411" }
+virtio-drivers = { path = "../.." }

+ 58 - 0
examples/riscv/Makefile

@@ -0,0 +1,58 @@
+arch ?= riscv64
+target := $(arch)imac-unknown-none-elf
+mode := release
+kernel := target/$(target)/$(mode)/riscv
+bin := target/$(target)/$(mode)/kernel.bin
+img := $(bin)
+
+sysroot := $(shell rustc --print sysroot)
+objdump := $(shell find $(sysroot) -name llvm-objdump) --arch-name=$(arch)
+objcopy := $(shell find $(sysroot) -name llvm-objcopy)
+
+BUILD_ARGS += --target $(target)
+ifeq ($(mode), release)
+	BUILD_ARGS += --release
+endif
+
+ifeq ($(arch), riscv32)
+	START_ADDR := 0x80400000
+else ifeq ($(arch), riscv64)
+	START_ADDR := 0x80200000
+endif
+
+.PHONY: kernel build clean qemu run env
+
+build: $(bin)
+
+env:
+	rustup component add llvm-tools-preview rustfmt
+	rustup target add $(target)
+
+kernel:
+	cargo build $(BUILD_ARGS)
+
+$(bin): kernel
+	$(objcopy) $(kernel) --strip-all -O binary $@
+
+asm:
+	$(objdump) -d $(kernel) | less
+
+sym:
+	$(objdump) -t $(kernel) | less
+
+header:
+	$(objdump) -x $(kernel) | less
+
+clean:
+	cargo clean
+
+qemu: $(bin)
+	qemu-system-$(arch) \
+		-machine virt \
+		-nographic \
+		-bios default \
+		-device loader,file=$(bin),addr=$(START_ADDR) \
+		-drive file=$(img),if=none,format=raw,id=x0 \
+		-device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
+
+run: build qemu

+ 44 - 0
examples/riscv/linker32.ld

@@ -0,0 +1,44 @@
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+BASE_ADDRESS = 0x80400000;
+
+SECTIONS
+{
+    /* Load the kernel at this address: "." means the current address */
+    . = BASE_ADDRESS;
+    start = .;
+
+    .text : {
+        stext = .;
+        *(.text.entry)
+        *(.text .text.*)
+        . = ALIGN(4K);
+        etext = .;
+    }
+
+    .rodata : {
+        srodata = .;
+        *(.rodata .rodata.*)
+        . = ALIGN(4K);
+        erodata = .;
+    }
+
+    .data : {
+        sdata = .;
+        *(.data .data.*)
+        edata = .;
+    }
+
+    .stack : {
+        *(.bss.stack)
+    }
+
+    .bss : {
+        sbss = .;
+        *(.bss .bss.*)
+        ebss = .;
+    }
+
+    PROVIDE(end = .);
+}

+ 44 - 0
examples/riscv/linker64.ld

@@ -0,0 +1,44 @@
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+
+BASE_ADDRESS = 0x80200000;
+
+SECTIONS
+{
+    /* Load the kernel at this address: "." means the current address */
+    . = BASE_ADDRESS;
+    start = .;
+
+    .text : {
+        stext = .;
+        *(.text.entry)
+        *(.text .text.*)
+        . = ALIGN(4K);
+        etext = .;
+    }
+
+    .rodata : {
+        srodata = .;
+        *(.rodata .rodata.*)
+        . = ALIGN(4K);
+        erodata = .;
+    }
+
+    .data : {
+        sdata = .;
+        *(.data .data.*)
+        edata = .;
+    }
+
+    .stack : {
+        *(.bss.stack)
+    }
+
+    .bss : {
+        sbss = .;
+        *(.bss .bss.*)
+        ebss = .;
+    }
+
+    PROVIDE(end = .);
+}

+ 1 - 0
examples/riscv/rust-toolchain

@@ -0,0 +1 @@
+nightly

+ 73 - 0
examples/riscv/src/main.rs

@@ -0,0 +1,73 @@
+#![no_std]
+#![no_main]
+
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate opensbi_rt;
+
+use device_tree::util::SliceRead;
+use device_tree::{DeviceTree, Node};
+use log::LevelFilter;
+use virtio_drivers::{DeviceType, VirtIOBlk, VirtIOHeader};
+
+mod virtio_impl;
+
+#[no_mangle]
+extern "C" fn main(_hartid: usize, device_tree_paddr: usize) {
+    log::set_max_level(LevelFilter::Info);
+    init_dt(device_tree_paddr);
+}
+
+fn init_dt(dtb: usize) {
+    info!("device tree @ {:#x}", dtb);
+    struct DtbHeader {
+        be_magic: u32,
+        be_size: u32,
+    }
+    let header = unsafe { &*(dtb as *const DtbHeader) };
+    let magic = u32::from_be(header.be_magic);
+    const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed;
+    assert_eq!(magic, DEVICE_TREE_MAGIC);
+    let size = u32::from_be(header.be_size);
+    let dtb_data = unsafe { core::slice::from_raw_parts(dtb as *const u8, size as usize) };
+    let dt = DeviceTree::load(dtb_data).expect("failed to parse device tree");
+    walk_dt_node(&dt.root);
+}
+
+fn walk_dt_node(dt: &Node) {
+    if let Ok(compatible) = dt.prop_str("compatible") {
+        if compatible == "virtio,mmio" {
+            virtio_probe(dt);
+        }
+    }
+    for child in dt.children.iter() {
+        walk_dt_node(child);
+    }
+}
+
+fn virtio_probe(node: &Node) {
+    if let Some(reg) = node.prop_raw("reg") {
+        let paddr = reg.as_slice().read_be_u64(0).unwrap();
+        let size = reg.as_slice().read_be_u64(8).unwrap();
+        let vaddr = paddr;
+        info!("walk dt addr={:#x}, size={:#x}", paddr, size);
+        let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
+        info!(
+            "Detected virtio device with vendor id {:#X}",
+            header.vendor_id()
+        );
+        info!("Device tree node {:?}", node);
+        match header.device_type() {
+            DeviceType::Block => virtio_blk(header),
+            t => warn!("Unrecognized virtio device: {:?}", t),
+        }
+    }
+}
+
+fn virtio_blk(header: &'static mut VirtIOHeader) {
+    let mut blk = VirtIOBlk::new(header).expect("failed to create blk driver");
+    let mut buf = [0u8; 512];
+    blk.read_block(0, &mut buf);
+    unimplemented!()
+}

+ 34 - 0
examples/riscv/src/virtio_impl.rs

@@ -0,0 +1,34 @@
+use core::sync::atomic::*;
+
+static DMA_PADDR: AtomicUsize = AtomicUsize::new(0x80300000);
+
+#[no_mangle]
+extern "C" fn virtio_alloc_dma(pages: usize) -> (VirtAddr, PhysAddr) {
+    let paddr = DMA_PADDR.fetch_add(0x1000 * pages, Ordering::SeqCst);
+    trace!(
+        "alloc DMA: vaddr={:#x}, paddr={:#x}, pages={}",
+        paddr,
+        paddr,
+        pages
+    );
+    (paddr, paddr)
+}
+
+#[no_mangle]
+extern "C" fn virtio_dealloc_dma(paddr: PhysAddr, pages: usize) -> bool {
+    trace!("dealloc DMA: paddr={:#x}, pages={}", paddr, pages);
+    true
+}
+
+#[no_mangle]
+extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr {
+    paddr
+}
+
+#[no_mangle]
+extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
+    vaddr
+}
+
+type VirtAddr = usize;
+type PhysAddr = usize;