From f754326d0a30a9b17cb59479624298cb75b30d5c Mon Sep 17 00:00:00 2001 From: Yifan Wu Date: Wed, 16 Dec 2020 10:18:38 +0800 Subject: [PATCH] virtio-blk worked. --- os/Cargo.toml | 2 + os/Makefile | 4 +- os/src/config.rs | 9 +++- os/src/drivers/block/mod.rs | 30 +++++++++++++ os/src/drivers/block/virtio_blk.rs | 71 ++++++++++++++++++++++++++++++ os/src/drivers/mod.rs | 3 ++ os/src/main.rs | 2 + os/src/mm/address.rs | 9 ++++ os/src/mm/frame_allocator.rs | 2 +- os/src/mm/memory_set.rs | 12 ++++- os/src/mm/mod.rs | 6 +-- os/src/timer.rs | 6 +-- 12 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 os/src/drivers/block/mod.rs create mode 100644 os/src/drivers/block/virtio_blk.rs create mode 100644 os/src/drivers/mod.rs diff --git a/os/Cargo.toml b/os/Cargo.toml index 588df758..668b7d3e 100644 --- a/os/Cargo.toml +++ b/os/Cargo.toml @@ -13,6 +13,8 @@ buddy_system_allocator = "0.6" spin = "0.7.0" bitflags = "1.2.1" xmas-elf = "0.7.0" +virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers" } + [features] board_qemu = [] diff --git a/os/Makefile b/os/Makefile index 1d13ccee..0d48329c 100644 --- a/os/Makefile +++ b/os/Makefile @@ -50,7 +50,9 @@ ifeq ($(BOARD),qemu) -machine virt \ -nographic \ -bios $(BOOTLOADER) \ - -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) + -device loader,file=$(KERNEL_BIN),addr=$(KERNEL_ENTRY_PA) \ + -drive file=fs.img,if=none,format=raw,id=x0 \ + -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 else @cp $(BOOTLOADER) $(BOOTLOADER).copy @dd if=$(KERNEL_BIN) of=$(BOOTLOADER).copy bs=128K seek=1 diff --git a/os/src/config.rs b/os/src/config.rs index 06efeb35..43fc8647 100644 --- a/os/src/config.rs +++ b/os/src/config.rs @@ -9,7 +9,12 @@ pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1; pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE; #[cfg(feature = "board_k210")] -pub const CPU_FREQ: usize = 10000000; +pub const CLOCK_FREQ: usize = 10000000; #[cfg(feature = "board_qemu")] -pub const CPU_FREQ: usize = 12500000; \ No newline at end of file +pub const CLOCK_FREQ: usize = 12500000; + +#[cfg(feature = "board_qemu")] +pub const MMIO: &[(usize, usize)] = &[ + (0x10001000, 0x10000), +]; \ No newline at end of file diff --git a/os/src/drivers/block/mod.rs b/os/src/drivers/block/mod.rs new file mode 100644 index 00000000..8ef275e0 --- /dev/null +++ b/os/src/drivers/block/mod.rs @@ -0,0 +1,30 @@ +mod virtio_blk; + +use lazy_static::*; +use alloc::sync::Arc; +use core::any::Any; + +pub trait BlockDevice : Send + Sync + Any { + fn read_block(&self, block_id: usize, buf: &mut [u8]); + fn write_block(&self, block_id: usize, buf: &[u8]); +} + +#[cfg(feature = "board_qemu")] +type BlockDeviceImpl = virtio_blk::VirtIOBlock; + +lazy_static! { + pub static ref BLOCK_DEVICE: Arc = Arc::new(BlockDeviceImpl::new()); +} + +pub fn block_device_test() { + let block_device = BLOCK_DEVICE.clone(); + let mut write_buffer = [0u8; 512]; + let mut read_buffer = [0u8; 512]; + for i in 0..512 { + for byte in write_buffer.iter_mut() { *byte = i as u8; } + block_device.write_block(i as usize, &write_buffer); + block_device.read_block(i as usize, &mut read_buffer); + assert_eq!(write_buffer, read_buffer); + } + println!("block device test passed!"); +} \ No newline at end of file diff --git a/os/src/drivers/block/virtio_blk.rs b/os/src/drivers/block/virtio_blk.rs new file mode 100644 index 00000000..1c7a1fe8 --- /dev/null +++ b/os/src/drivers/block/virtio_blk.rs @@ -0,0 +1,71 @@ +use virtio_drivers::{VirtIOBlk, VirtIOHeader}; +use crate::mm::{ + PhysAddr, + VirtAddr, + frame_alloc, + frame_dealloc, + PhysPageNum, + FrameTracker, + StepByOne, +}; +use super::BlockDevice; +use spin::Mutex; +use alloc::vec::Vec; +use lazy_static::*; + +const VIRTIO0: usize = 0x10001000; + +pub struct VirtIOBlock(Mutex>); + +lazy_static! { + static ref QUEUE_FRAMES: Mutex> = Mutex::new(Vec::new()); +} + +impl BlockDevice for VirtIOBlock { + fn read_block(&self, block_id: usize, buf: &mut [u8]) { + self.0.lock().read_block(block_id, buf).expect("Error when reading VirtIOBlk"); + } + fn write_block(&self, block_id: usize, buf: &[u8]) { + self.0.lock().write_block(block_id, buf).expect("Error when writing VirtIOBlk"); + } +} + +impl VirtIOBlock { + pub fn new() -> Self { + Self(Mutex::new(VirtIOBlk::new( + unsafe { &mut *(VIRTIO0 as *mut VirtIOHeader) } + ).unwrap())) + } +} + +#[no_mangle] +pub extern "C" fn virtio_dma_alloc(pages: usize) -> PhysAddr { + let mut ppn_base = PhysPageNum(0); + for i in 0..pages { + let frame = frame_alloc().unwrap(); + if i == 0 { ppn_base = frame.ppn; } + assert_eq!(frame.ppn.0, ppn_base.0 + i); + QUEUE_FRAMES.lock().push(frame); + } + ppn_base.into() +} + +#[no_mangle] +pub extern "C" fn virtio_dma_dealloc(pa: PhysAddr, pages: usize) -> i32 { + let mut ppn_base: PhysPageNum = pa.into(); + for _ in 0..pages { + frame_dealloc(ppn_base); + ppn_base.step(); + } + 0 +} + +#[no_mangle] +pub extern "C" fn virtio_phys_to_virt(paddr: PhysAddr) -> VirtAddr { + VirtAddr(paddr.0) +} + +#[no_mangle] +pub extern "C" fn virtio_virt_to_phys(vaddr: VirtAddr) -> PhysAddr { + PhysAddr(vaddr.0) +} diff --git a/os/src/drivers/mod.rs b/os/src/drivers/mod.rs new file mode 100644 index 00000000..cf4d35b6 --- /dev/null +++ b/os/src/drivers/mod.rs @@ -0,0 +1,3 @@ +mod block; + +pub use block::{BLOCK_DEVICE, block_device_test}; \ No newline at end of file diff --git a/os/src/main.rs b/os/src/main.rs index 02ebaeb2..76ef69c2 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -23,6 +23,7 @@ mod task; mod timer; mod mm; mod fs; +mod drivers; global_asm!(include_str!("entry.asm")); global_asm!(include_str!("link_app.S")); @@ -43,6 +44,7 @@ pub fn rust_main() -> ! { println!("[kernel] Hello, world!"); mm::init(); mm::remap_test(); + drivers::block_device_test(); task::add_initproc(); println!("after initproc!"); trap::init(); diff --git a/os/src/mm/address.rs b/os/src/mm/address.rs index 5a3d6161..05d04abd 100644 --- a/os/src/mm/address.rs +++ b/os/src/mm/address.rs @@ -3,15 +3,19 @@ use super::PageTableEntry; use core::fmt::{self, Debug, Formatter}; /// Definitions +#[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysAddr(pub usize); +#[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtAddr(pub usize); +#[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct PhysPageNum(pub usize); +#[repr(C)] #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] pub struct VirtPageNum(pub usize); @@ -144,6 +148,11 @@ impl StepByOne for VirtPageNum { self.0 += 1; } } +impl StepByOne for PhysPageNum { + fn step(&mut self) { + self.0 += 1; + } +} #[derive(Copy, Clone)] pub struct SimpleRange where diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index 3cbc5623..2cb6427b 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -108,7 +108,7 @@ pub fn frame_alloc() -> Option { .map(|ppn| FrameTracker::new(ppn)) } -fn frame_dealloc(ppn: PhysPageNum) { +pub fn frame_dealloc(ppn: PhysPageNum) { FRAME_ALLOCATOR .lock() .dealloc(ppn); diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 9dce433f..3f2b8aca 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -13,7 +13,8 @@ use crate::config::{ PAGE_SIZE, TRAMPOLINE, TRAP_CONTEXT, - USER_STACK_SIZE + USER_STACK_SIZE, + MMIO, }; extern "C" { @@ -126,6 +127,15 @@ impl MemorySet { MapType::Identical, MapPermission::R | MapPermission::W, ), None); + println!("mapping memory-mapped registers"); + for pair in MMIO { + memory_set.push(MapArea::new( + (*pair).0.into(), + ((*pair).0 + (*pair).1).into(), + MapType::Identical, + MapPermission::R | MapPermission::W, + ), None); + } memory_set } /// Include sections in elf and trampoline and TrapContext and user stack, diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs index 350b4fad..db49a659 100644 --- a/os/src/mm/mod.rs +++ b/os/src/mm/mod.rs @@ -5,9 +5,9 @@ mod page_table; mod memory_set; use page_table::{PageTable, PTEFlags}; -use address::{VPNRange, StepByOne}; -pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum}; -pub use frame_allocator::{FrameTracker, frame_alloc}; +use address::VPNRange; +pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum, StepByOne}; +pub use frame_allocator::{FrameTracker, frame_alloc, frame_dealloc,}; pub use page_table::{ PageTableEntry, translated_byte_buffer, diff --git a/os/src/timer.rs b/os/src/timer.rs index 612d51af..92d50e3a 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -1,6 +1,6 @@ use riscv::register::time; use crate::sbi::set_timer; -use crate::config::CPU_FREQ; +use crate::config::CLOCK_FREQ; const TICKS_PER_SEC: usize = 100; const MSEC_PER_SEC: usize = 1000; @@ -10,9 +10,9 @@ pub fn get_time() -> usize { } pub fn get_time_ms() -> usize { - time::read() / (CPU_FREQ / MSEC_PER_SEC) + time::read() / (CLOCK_FREQ / MSEC_PER_SEC) } pub fn set_next_trigger() { - set_timer(get_time() + CPU_FREQ / TICKS_PER_SEC); + set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC); } \ No newline at end of file