mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-26 03:13:36 +04:00
virtio-blk worked.
This commit is contained in:
parent
8e178c0080
commit
f754326d0a
@ -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 = []
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
pub const CLOCK_FREQ: usize = 12500000;
|
||||
|
||||
#[cfg(feature = "board_qemu")]
|
||||
pub const MMIO: &[(usize, usize)] = &[
|
||||
(0x10001000, 0x10000),
|
||||
];
|
30
os/src/drivers/block/mod.rs
Normal file
30
os/src/drivers/block/mod.rs
Normal file
@ -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<dyn BlockDevice> = 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!");
|
||||
}
|
71
os/src/drivers/block/virtio_blk.rs
Normal file
71
os/src/drivers/block/virtio_blk.rs
Normal file
@ -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<VirtIOBlk<'static>>);
|
||||
|
||||
lazy_static! {
|
||||
static ref QUEUE_FRAMES: Mutex<Vec<FrameTracker>> = 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)
|
||||
}
|
3
os/src/drivers/mod.rs
Normal file
3
os/src/drivers/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
mod block;
|
||||
|
||||
pub use block::{BLOCK_DEVICE, block_device_test};
|
@ -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();
|
||||
|
@ -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<T> where
|
||||
|
@ -108,7 +108,7 @@ pub fn frame_alloc() -> Option<FrameTracker> {
|
||||
.map(|ppn| FrameTracker::new(ppn))
|
||||
}
|
||||
|
||||
fn frame_dealloc(ppn: PhysPageNum) {
|
||||
pub fn frame_dealloc(ppn: PhysPageNum) {
|
||||
FRAME_ALLOCATOR
|
||||
.lock()
|
||||
.dealloc(ppn);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user