mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
VirtIO网卡能够正常发送、接收数据 (#204)
* virtio-net小修改 * 移动volatile.rs到libs文件夹 * 使用virtio-drivers 0.3.0 * bugfix: 初始化BAR之后,未正确设置command register的问题 --------- Co-authored-by: longjin <longjin@dragonos.org>
This commit is contained in:
parent
4454d1a2dd
commit
73c607aadd
@ -12,7 +12,7 @@ crate-type = ["staticlib"]
|
||||
[dependencies]
|
||||
x86_64 = "0.14.10"
|
||||
bitflags = "1.3.2"
|
||||
virtio-drivers = "0.2.0"
|
||||
virtio-drivers = "0.3.0"
|
||||
# 一个无锁MPSC队列
|
||||
thingbuf = { version = "0.1.3", default-features = false, features = ["alloc"] }
|
||||
# smoltcp 0.9.1
|
||||
|
@ -46,7 +46,7 @@ bitflags! {
|
||||
|
||||
bitflags! {
|
||||
/// The command register in PCI configuration space.
|
||||
pub struct Command: u16 {
|
||||
pub struct CommandRegister: u16 {
|
||||
/// The device can respond to I/O Space accesses.
|
||||
const IO_SPACE = 1 << 0;
|
||||
/// The device can respond to Memory Space accesses.
|
||||
@ -131,9 +131,10 @@ impl Display for PciError {
|
||||
impl DeviceFunction {
|
||||
/// Returns whether the device and function numbers are valid, i.e. the device is between 0 and
|
||||
/// 31, and the function is between 0 and 7.
|
||||
///@brief 检测DeviceFunction实例是否有效
|
||||
///@param self
|
||||
///@return bool 是否有效
|
||||
/// @brief 检测DeviceFunction实例是否有效
|
||||
/// @param self
|
||||
/// @return bool 是否有效
|
||||
#[allow(dead_code)]
|
||||
pub fn valid(&self) -> bool {
|
||||
self.device < 32 && self.function < 8
|
||||
}
|
||||
@ -449,6 +450,7 @@ pub struct CapabilityInfo {
|
||||
/// The third and fourth bytes of the capability, to save reading them again.
|
||||
pub private_header: u16,
|
||||
}
|
||||
|
||||
/// Iterator over capabilities for a device.
|
||||
/// 创建迭代器以遍历PCI设备的capability
|
||||
#[derive(Debug)]
|
||||
@ -492,3 +494,28 @@ impl Iterator for CapabilityIterator {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 设置PCI Config Space里面的Command Register
|
||||
///
|
||||
/// @param device_function 设备
|
||||
/// @param value command register要被设置成的值
|
||||
pub fn set_command_register(device_function: &DeviceFunction, value: CommandRegister) {
|
||||
unsafe {
|
||||
pci_write_config(
|
||||
device_function.bus,
|
||||
device_function.device,
|
||||
device_function.function,
|
||||
STATUS_COMMAND_OFFSET,
|
||||
value.bits().into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
/// @brief 使能对PCI Memory/IO空间的写入,使能PCI设备作为主设备(主动进行Memory的写入等,msix中断使用到)
|
||||
///
|
||||
/// @param device_function 设备
|
||||
pub fn pci_enable_master(device_function: DeviceFunction) {
|
||||
set_command_register(
|
||||
&device_function,
|
||||
CommandRegister::IO_SPACE | CommandRegister::MEMORY_SPACE | CommandRegister::BUS_MASTER,
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
pub mod transport_pci;
|
||||
pub mod virtio;
|
||||
pub mod virtio_impl;
|
||||
pub mod volatile;
|
||||
|
@ -1,12 +1,13 @@
|
||||
//! PCI transport for VirtIO.
|
||||
use super::volatile::{
|
||||
volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
|
||||
};
|
||||
use crate::driver::pci::pci::{
|
||||
capabilities_offset, pci_bar_init, CapabilityIterator, DeviceFunction, PciDeviceBar, PciError,
|
||||
PCI_CAP_ID_VNDR,
|
||||
capabilities_offset, pci_bar_init, pci_enable_master, CapabilityIterator, DeviceFunction,
|
||||
PciDeviceBar, PciError, PCI_CAP_ID_VNDR,
|
||||
};
|
||||
use crate::include::bindings::bindings::pci_read_config;
|
||||
|
||||
use crate::libs::volatile::{
|
||||
volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
|
||||
};
|
||||
use core::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem::{align_of, size_of},
|
||||
@ -14,9 +15,10 @@ use core::{
|
||||
};
|
||||
use virtio_drivers::{
|
||||
transport::{DeviceStatus, DeviceType, Transport},
|
||||
Error, Hal, PhysAddr, VirtAddr,
|
||||
Error, Hal, PhysAddr,
|
||||
};
|
||||
|
||||
type VirtAddr = usize;
|
||||
/// The PCI vendor ID for VirtIO devices.
|
||||
/// PCI Virtio设备的vendor ID
|
||||
const VIRTIO_VENDOR_ID: u16 = 0x1af4;
|
||||
@ -119,8 +121,9 @@ impl PciTransport {
|
||||
device_function: device_function,
|
||||
next_capability_offset: capabilities_offset(device_function),
|
||||
};
|
||||
let device_bar = pci_bar_init(device_function)?;
|
||||
|
||||
let device_bar = pci_bar_init(device_function)?;
|
||||
pci_enable_master(device_function);
|
||||
for capability in device_capability {
|
||||
if capability.id != PCI_CAP_ID_VNDR {
|
||||
continue;
|
||||
@ -197,6 +200,7 @@ impl PciTransport {
|
||||
notify_off_multiplier,
|
||||
));
|
||||
}
|
||||
//kdebug!("notify.offset={},notify.length={}",notify_cfg.offset,notify_cfg.length);
|
||||
let notify_region = get_bar_region_slice::<_>(&device_bar, ¬ify_cfg)?;
|
||||
let isr_status = get_bar_region::<_>(
|
||||
&device_bar,
|
||||
@ -282,7 +286,9 @@ impl Transport for PciTransport {
|
||||
fn set_guest_page_size(&mut self, _guest_page_size: u32) {
|
||||
// No-op, the PCI transport doesn't care.
|
||||
}
|
||||
|
||||
fn requires_legacy_layout(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn queue_set(
|
||||
&mut self,
|
||||
queue: u16,
|
||||
@ -293,6 +299,10 @@ impl Transport for PciTransport {
|
||||
) {
|
||||
// Safe because the common config pointer is valid and we checked in get_bar_region that it
|
||||
// was aligned.
|
||||
// kdebug!("queue_select={}",queue);
|
||||
// kdebug!("queue_size={}",size as u16);
|
||||
// kdebug!("queue_desc={:#x}",descriptors as u64);
|
||||
// kdebug!("driver_area={:#x}",driver_area);
|
||||
unsafe {
|
||||
volwrite!(self.common_cfg, queue_select, queue);
|
||||
volwrite!(self.common_cfg, queue_size, size as u16);
|
||||
@ -307,7 +317,6 @@ impl Transport for PciTransport {
|
||||
// Safe because the common config pointer is valid and we checked in get_bar_region that it
|
||||
// was aligned.
|
||||
unsafe {
|
||||
volwrite!(self.common_cfg, queue_enable, 0);
|
||||
volwrite!(self.common_cfg, queue_select, queue);
|
||||
volwrite!(self.common_cfg, queue_size, 0);
|
||||
volwrite!(self.common_cfg, queue_desc, 0);
|
||||
@ -355,8 +364,13 @@ impl Transport for PciTransport {
|
||||
}
|
||||
}
|
||||
|
||||
/// `virtio_pci_common_cfg`, see 4.1.4.3 "Common configuration structure layout".
|
||||
///
|
||||
impl Drop for PciTransport {
|
||||
fn drop(&mut self) {
|
||||
// Reset the device when the transport is dropped.
|
||||
self.set_status(DeviceStatus::empty())
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct CommonCfg {
|
||||
device_feature_select: Volatile<u32>,
|
||||
@ -488,6 +502,7 @@ fn get_bar_region<T>(
|
||||
{
|
||||
return Err(VirtioPciError::BarOffsetOutOfRange);
|
||||
}
|
||||
//kdebug!("Chossed bar ={},used={}",struct_info.bar,struct_info.offset + struct_info.length);
|
||||
let vaddr = (bar_info
|
||||
.virtual_address()
|
||||
.ok_or(VirtioPciError::BarGetVaddrFailed)?) as usize
|
||||
@ -498,18 +513,25 @@ fn get_bar_region<T>(
|
||||
alignment: align_of::<T>(),
|
||||
});
|
||||
}
|
||||
Ok(NonNull::new((vaddr) as _).unwrap())
|
||||
let vaddr = NonNull::new(vaddr as *mut u8).unwrap();
|
||||
Ok(vaddr.cast())
|
||||
}
|
||||
|
||||
///@brief 获取虚拟地址并将其转化为对应类型的指针
|
||||
///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息
|
||||
///@brief 获取虚拟地址并将其转化为对应类型的
|
||||
///@param device_bar 存储bar信息的结构体 struct_info 存储cfg空间的位置信息切片的指针
|
||||
///@return Result<NonNull<[T]>, VirtioPciError> 成功则返回对应类型的指针切片,失败则返回Error
|
||||
fn get_bar_region_slice<T>(
|
||||
device_bar: &PciDeviceBar,
|
||||
struct_info: &VirtioCapabilityInfo,
|
||||
) -> Result<NonNull<[T]>, VirtioPciError> {
|
||||
let ptr = get_bar_region::<T>(device_bar, struct_info)?;
|
||||
let raw_slice =
|
||||
ptr::slice_from_raw_parts_mut(ptr.as_ptr(), struct_info.length as usize / size_of::<T>());
|
||||
Ok(NonNull::new(raw_slice).unwrap())
|
||||
// let raw_slice =
|
||||
// ptr::slice_from_raw_parts_mut(ptr.as_ptr(), struct_info.length as usize / size_of::<T>());
|
||||
Ok(nonnull_slice_from_raw_parts(
|
||||
ptr,
|
||||
struct_info.length as usize / size_of::<T>(),
|
||||
))
|
||||
}
|
||||
fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
|
||||
NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
|
||||
}
|
||||
|
@ -9,4 +9,4 @@
|
||||
// 获取virtio-net 设备
|
||||
uint8_t get_virtio_net_device(uint8_t * bus, uint8_t *device,uint8_t * function);
|
||||
//寻找并加载所有virtio设备的驱动(目前只有virtio-net,但其他virtio设备后续也可添加)
|
||||
extern void c_virtio_probe();
|
||||
void c_virtio_probe();
|
||||
|
@ -90,18 +90,41 @@ fn virtio_net<T: Transport>(transport: T) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
// let mut buf = [0u8; 0x100];
|
||||
let mut buf = [0u8; 0x100];
|
||||
// let len = match driver_net.recv(&mut buf)
|
||||
// {
|
||||
// Ok(len) =>{len},
|
||||
// Err(_) =>{kerror!("virtio_net recv failed");return;}
|
||||
// };
|
||||
// kdebug!("recv: {:?}", &buf[..len]);
|
||||
// match driver_net.send(&buf[..len])
|
||||
// {
|
||||
// Ok(_) =>{kdebug!("virtio_net send success");},
|
||||
// Err(_) =>{kerror!("virtio_net send failed");return;},
|
||||
match driver_net.can_send() {
|
||||
true => {
|
||||
kdebug!("Virtio-net can send");
|
||||
}
|
||||
false => {
|
||||
kdebug!("Virtio-net can not send");
|
||||
}
|
||||
}
|
||||
// match driver_net.can_recv() {
|
||||
// true => {
|
||||
// kdebug!("can recv")
|
||||
// }
|
||||
// false => {
|
||||
// kdebug!("can not recv");
|
||||
// }
|
||||
// }
|
||||
|
||||
let len = 100;
|
||||
//kdebug!("recv: {:?}", &buf[..len]);
|
||||
match driver_net.send(&buf[..len]) {
|
||||
Ok(_) => {
|
||||
kdebug!("virtio_net send success");
|
||||
}
|
||||
Err(_) => {
|
||||
kerror!("virtio_net send failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mac = driver_net.mac();
|
||||
kdebug!("virtio_net MAC={:?}", mac);
|
||||
kdebug!("virtio-net test finished");
|
||||
|
@ -1,63 +1,57 @@
|
||||
/// 为virtio-drivers库提供的操作系统接口
|
||||
use crate::include::bindings::bindings::{
|
||||
alloc_pages, free_pages, memory_management_struct, Page, PAGE_2M_SHIFT, PAGE_2M_SIZE,
|
||||
PAGE_OFFSET, PAGE_SHARED, ZONE_NORMAL,
|
||||
};
|
||||
|
||||
use crate::mm::virt_2_phys;
|
||||
use core::mem::size_of;
|
||||
use core::ptr::NonNull;
|
||||
use virtio_drivers::{BufferDirection, Hal, PhysAddr, VirtAddr, PAGE_SIZE};
|
||||
|
||||
use virtio_drivers::{BufferDirection, Hal, PhysAddr, PAGE_SIZE};
|
||||
pub struct HalImpl;
|
||||
impl Hal for HalImpl {
|
||||
/// @brief 申请用于DMA的内存页
|
||||
/// @param pages 页数(4k一页)
|
||||
/// @return PhysAddr 获得的内存页的初始物理地址
|
||||
fn dma_alloc(pages: usize) -> PhysAddr {
|
||||
let reminder = pages * PAGE_SIZE % (PAGE_2M_SIZE as usize);
|
||||
let page_num = if reminder > 0 {
|
||||
(pages * PAGE_SIZE / (PAGE_2M_SIZE as usize) + 1) as i32
|
||||
} else {
|
||||
(pages * PAGE_SIZE / (PAGE_2M_SIZE as usize)) as i32
|
||||
};
|
||||
|
||||
fn dma_alloc(pages: usize, _direction: BufferDirection) -> (PhysAddr, NonNull<u8>) {
|
||||
let page_num = (pages * PAGE_SIZE - 1 + PAGE_2M_SIZE as usize) / PAGE_2M_SIZE as usize;
|
||||
unsafe {
|
||||
let pa = alloc_pages(ZONE_NORMAL, page_num, PAGE_SHARED as u64);
|
||||
let pa = alloc_pages(ZONE_NORMAL, page_num as i32, PAGE_SHARED as u64);
|
||||
let page = *pa;
|
||||
//kdebug!("alloc pages num:{},Phyaddr={}",page_num,page.addr_phys);
|
||||
return page.addr_phys as PhysAddr;
|
||||
//kdebug!("alloc pages num:{},Phyaddr={:#x}",pages,page.addr_phys);
|
||||
(
|
||||
page.addr_phys as PhysAddr,
|
||||
NonNull::new((page.addr_phys as PhysAddr + PAGE_OFFSET as usize) as _).unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
/// @brief 释放用于DMA的内存页
|
||||
/// @param paddr 起始物理地址 pages 页数(4k一页)
|
||||
/// @return i32 0表示成功
|
||||
fn dma_dealloc(paddr: PhysAddr, pages: usize) -> i32 {
|
||||
let reminder = pages * PAGE_SIZE % (PAGE_2M_SIZE as usize);
|
||||
let page_num = if reminder > 0 {
|
||||
(pages * PAGE_SIZE / (PAGE_2M_SIZE as usize) + 1) as i32
|
||||
} else {
|
||||
(pages * PAGE_SIZE / (PAGE_2M_SIZE as usize)) as i32
|
||||
};
|
||||
fn dma_dealloc(paddr: PhysAddr, _vaddr: NonNull<u8>, pages: usize) -> i32 {
|
||||
let page_num = (pages * PAGE_SIZE - 1 + PAGE_2M_SIZE as usize) / PAGE_2M_SIZE as usize;
|
||||
unsafe {
|
||||
let pa = (memory_management_struct.pages_struct as usize
|
||||
+ (paddr >> PAGE_2M_SHIFT) * size_of::<Page>()) as *mut Page;
|
||||
//kdebug!("free pages num:{},Phyaddr={}",page_num,paddr);
|
||||
free_pages(pa, page_num);
|
||||
free_pages(pa, page_num as i32);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/// @brief 物理地址转换为虚拟地址
|
||||
/// @brief mmio物理地址转换为虚拟地址,不需要使用
|
||||
/// @param paddr 起始物理地址
|
||||
/// @return VirtAddr 虚拟地址
|
||||
fn phys_to_virt(paddr: PhysAddr) -> VirtAddr {
|
||||
paddr + PAGE_OFFSET as usize
|
||||
/// @return NonNull<u8> 虚拟地址的指针
|
||||
fn mmio_phys_to_virt(_paddr: PhysAddr, _size: usize) -> NonNull<u8> {
|
||||
NonNull::new((0) as _).unwrap()
|
||||
}
|
||||
/// @brief 与真实物理设备共享
|
||||
/// @param buffer 要共享的buffer _direction:设备到driver或driver到设备
|
||||
/// @return buffer在内存中的物理地址
|
||||
fn share(buffer: NonNull<[u8]>, _direction: BufferDirection) -> PhysAddr {
|
||||
let vaddr = buffer.as_ptr() as *mut u8 as usize;
|
||||
//kdebug!("virt:{:x}", vaddr);
|
||||
// Nothing to do, as the host already has access to all memory.
|
||||
virt_to_phys(vaddr)
|
||||
virt_2_phys(vaddr)
|
||||
}
|
||||
/// @brief 停止共享(让主机可以访问全部内存的话什么都不用做)
|
||||
fn unshare(_paddr: PhysAddr, _buffer: NonNull<[u8]>, _direction: BufferDirection) {
|
||||
@ -65,10 +59,3 @@ impl Hal for HalImpl {
|
||||
// anywhere else.
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 虚拟地址转换为物理地址
|
||||
/// @param vaddr 虚拟地址
|
||||
/// @return PhysAddr 物理地址
|
||||
fn virt_to_phys(vaddr: VirtAddr) -> PhysAddr {
|
||||
vaddr - PAGE_OFFSET as usize
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ pub mod zero_dev;
|
||||
|
||||
use super::vfs::{
|
||||
core::{generate_inode_id, ROOT_INODE},
|
||||
FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus, file::FileMode,
|
||||
file::FileMode,
|
||||
FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus,
|
||||
};
|
||||
use crate::{
|
||||
include::bindings::bindings::{EEXIST, EISDIR, ENOENT, ENOTDIR, ENOTSUP},
|
||||
kdebug, kerror,
|
||||
kerror,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
time::TimeSpec,
|
||||
};
|
||||
@ -231,7 +232,7 @@ impl DevFSInode {
|
||||
|
||||
impl LockedDevFSInode {
|
||||
pub fn add_dir(&self, name: &str) -> Result<(), i32> {
|
||||
let guard:SpinLockGuard<DevFSInode> = self.0.lock();
|
||||
let guard: SpinLockGuard<DevFSInode> = self.0.lock();
|
||||
|
||||
if guard.children.contains_key(name) {
|
||||
return Err(-(EEXIST as i32));
|
||||
@ -270,10 +271,14 @@ impl LockedDevFSInode {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn do_create_with_data(&self, mut guard: SpinLockGuard<DevFSInode>,_name: &str,
|
||||
fn do_create_with_data(
|
||||
&self,
|
||||
mut guard: SpinLockGuard<DevFSInode>,
|
||||
_name: &str,
|
||||
_file_type: FileType,
|
||||
_mode: u32,
|
||||
_data: usize,) -> Result<Arc<dyn IndexNode>, i32>{
|
||||
_data: usize,
|
||||
) -> Result<Arc<dyn IndexNode>, i32> {
|
||||
if guard.metadata.file_type != FileType::Dir {
|
||||
return Err(-(ENOTDIR as i32));
|
||||
}
|
||||
@ -313,7 +318,6 @@ impl LockedDevFSInode {
|
||||
// 将子inode插入父inode的B树中
|
||||
guard.children.insert(String::from(_name), result.clone());
|
||||
return Ok(result);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,7 +333,7 @@ impl IndexNode for LockedDevFSInode {
|
||||
fn close(&self, _data: &mut super::vfs::FilePrivateData) -> Result<(), i32> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
fn create_with_data(
|
||||
&self,
|
||||
name: &str,
|
||||
@ -338,7 +342,7 @@ impl IndexNode for LockedDevFSInode {
|
||||
data: usize,
|
||||
) -> Result<Arc<dyn IndexNode>, i32> {
|
||||
// 获取当前inode
|
||||
let guard:SpinLockGuard<DevFSInode> = self.0.lock();
|
||||
let guard: SpinLockGuard<DevFSInode> = self.0.lock();
|
||||
// 如果当前inode不是文件夹,则返回
|
||||
return self.do_create_with_data(guard, name, file_type, mode, data);
|
||||
}
|
||||
|
@ -10,14 +10,15 @@ use alloc::{
|
||||
|
||||
use crate::{
|
||||
filesystem::vfs::{
|
||||
core::generate_inode_id, file::{FilePrivateData, FileMode}, FileSystem, FileType, IndexNode, InodeId,
|
||||
Metadata, PollStatus,
|
||||
core::generate_inode_id,
|
||||
file::{FileMode, FilePrivateData},
|
||||
FileSystem, FileType, IndexNode, InodeId, Metadata, PollStatus,
|
||||
},
|
||||
include::bindings::bindings::{
|
||||
EFAULT, EINVAL, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY, ENOTSUP, EPERM, EROFS,
|
||||
},
|
||||
io::{device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
||||
kdebug, kerror,
|
||||
kerror,
|
||||
libs::{
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
vec_cursor::VecCursor,
|
||||
@ -1539,7 +1540,6 @@ impl IndexNode for LockedFATInode {
|
||||
let r = dir.remove(guard.fs.upgrade().unwrap().clone(), name, true);
|
||||
drop(target_guard);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
fn rmdir(&self, name: &str) -> Result<(), i32> {
|
||||
|
@ -11,5 +11,6 @@ pub mod semaphore;
|
||||
pub mod spinlock;
|
||||
pub mod vec_cursor;
|
||||
#[macro_use]
|
||||
pub mod volatile_io;
|
||||
pub mod volatile;
|
||||
pub mod wait_queue;
|
||||
|
||||
|
@ -1,8 +1,76 @@
|
||||
/// An MMIO register which can only be read from.
|
||||
macro_rules! volatile_read {
|
||||
($data: expr) => {
|
||||
unsafe { core::ptr::read_volatile(core::ptr::addr_of!($data)) }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! volatile_write {
|
||||
($data: expr, $value: expr) => {
|
||||
unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($data), $value) }
|
||||
};
|
||||
}
|
||||
|
||||
/// @brief: 用于volatile设置某些bits
|
||||
/// @param val: 设置这些位
|
||||
/// @param flag: true表示设置这些位为1; false表示设置这些位为0;
|
||||
macro_rules! volatile_set_bit {
|
||||
($data: expr, $val: expr, $flag: expr) => {
|
||||
volatile_write!(
|
||||
$data,
|
||||
match $flag {
|
||||
true => core::ptr::read_volatile(core::ptr::addr_of!($data)) | $val,
|
||||
false => core::ptr::read_volatile(core::ptr::addr_of!($data)) & (!$val),
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// @param data: volatile变量
|
||||
/// @param bits: 置1的位才有效,表示写这些位
|
||||
/// @param val: 要写的值
|
||||
/// 比如: 写 x 的 2至8bit, 为 10, 可以这么写 volatile_write_bit(x, (1<<8)-(1<<2), 10<<2);
|
||||
macro_rules! volatile_write_bit {
|
||||
($data: expr, $bits: expr, $val: expr) => {
|
||||
volatile_set_bit!($data, $bits, false);
|
||||
volatile_set_bit!($data, ($val) & ($bits), true);
|
||||
};
|
||||
}
|
||||
|
||||
/// 以下代码来自于virtio-drivers 0.2.0
|
||||
/// 在对已经MMIO映射对虚拟地址的寄存器的操作中,我们经常遇到有的寄存器是只读或可读写的
|
||||
/// 那么我们就可以使用结构体ReadOnly WriteOnly Volatile对其进行区分
|
||||
/// 例:
|
||||
/// #[repr(C)]
|
||||
/// struct CommonCfg {
|
||||
/// device_feature_select: Volatile<u32>,
|
||||
/// device_feature: ReadOnly<u32>,
|
||||
/// driver_feature_select: Volatile<u32>,
|
||||
/// driver_feature: Volatile<u32>,
|
||||
/// msix_config: Volatile<u16>,
|
||||
/// num_queues: ReadOnly<u16>,
|
||||
/// device_status: Volatile<u8>,
|
||||
/// config_generation: ReadOnly<u8>,
|
||||
/// queue_select: Volatile<u16>,
|
||||
/// queue_size: Volatile<u16>,
|
||||
/// queue_msix_vector: Volatile<u16>,
|
||||
/// queue_enable: Volatile<u16>,
|
||||
/// queue_notify_off: Volatile<u16>,
|
||||
/// queue_desc: Volatile<u64>,
|
||||
/// queue_driver: Volatile<u64>,
|
||||
/// queue_device: Volatile<u64>,
|
||||
/// }
|
||||
///
|
||||
/// 对CommonCfg里面的某个寄存器进行读写:
|
||||
/// volwrite!(self.common_cfg, queue_enable, 0);
|
||||
///
|
||||
/// 这样做不仅使代码的可读性提高了,也避免了对只读寄存器进行写入的误操作
|
||||
|
||||
/// 只读寄存器
|
||||
#[derive(Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct ReadOnly<T: Copy>(T);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T: Copy> ReadOnly<T> {
|
||||
/// Construct a new instance for testing.
|
||||
pub fn new(value: T) -> Self {
|
||||
@ -10,16 +78,17 @@ impl<T: Copy> ReadOnly<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An MMIO register which can only be written to.
|
||||
/// 只写寄存器
|
||||
#[derive(Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct WriteOnly<T: Copy>(T);
|
||||
|
||||
/// An MMIO register which may be both read and written.
|
||||
/// 写读寄存器
|
||||
#[derive(Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct Volatile<T: Copy>(T);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T: Copy> Volatile<T> {
|
||||
/// Construct a new instance for testing.
|
||||
pub fn new(value: T) -> Self {
|
@ -1,37 +0,0 @@
|
||||
macro_rules! volatile_read {
|
||||
($data: expr) => {
|
||||
unsafe { core::ptr::read_volatile(core::ptr::addr_of!($data)) }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! volatile_write {
|
||||
($data: expr, $value: expr) => {
|
||||
unsafe { core::ptr::write_volatile(core::ptr::addr_of_mut!($data), $value) }
|
||||
};
|
||||
}
|
||||
|
||||
/// @brief: 用于volatile设置某些bits
|
||||
/// @param val: 设置这些位
|
||||
/// @param flag: true表示设置这些位为1; false表示设置这些位为0;
|
||||
macro_rules! volatile_set_bit {
|
||||
($data: expr, $val: expr, $flag: expr) => {
|
||||
volatile_write!(
|
||||
$data,
|
||||
match $flag {
|
||||
true => core::ptr::read_volatile(core::ptr::addr_of!($data)) | $val,
|
||||
false => core::ptr::read_volatile(core::ptr::addr_of!($data)) & (!$val),
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// @param data: volatile变量
|
||||
/// @param bits: 置1的位才有效,表示写这些位
|
||||
/// @param val: 要写的值
|
||||
/// 比如: 写 x 的 2至8bit, 为 10, 可以这么写 volatile_write_bit(x, (1<<8)-(1<<2), 10<<2);
|
||||
macro_rules! volatile_write_bit {
|
||||
($data: expr, $bits: expr, $val: expr) => {
|
||||
volatile_set_bit!($data, $bits, false);
|
||||
volatile_set_bit!($data, ($val) & ($bits), true);
|
||||
};
|
||||
}
|
@ -9,7 +9,7 @@ ARCH="x86_64"
|
||||
# 请根据自己的需要,在-d 后方加入所需的trace事件
|
||||
|
||||
# 标准的trace events
|
||||
qemu_trace_std=cpu_reset,guest_errors,exec,cpu
|
||||
qemu_trace_std=cpu_reset,guest_errors,exec,cpu,trace:virtio*
|
||||
# 调试usb的trace
|
||||
qemu_trace_usb=trace:usb_xhci_reset,trace:usb_xhci_run,trace:usb_xhci_stop,trace:usb_xhci_irq_msi,trace:usb_xhci_irq_msix,trace:usb_xhci_port_reset,trace:msix_write_config,trace:usb_xhci_irq_msix,trace:usb_xhci_irq_msix_use,trace:usb_xhci_irq_msix_unuse,trace:usb_xhci_irq_msi,trace:usb_xhci_*
|
||||
qemu_accel=kvm
|
||||
@ -29,7 +29,7 @@ QEMU_RTC_CLOCK="clock=host,base=localtime"
|
||||
QEMU_SERIAL="file:../serial_opt.txt"
|
||||
QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
|
||||
|
||||
QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,model=virtio -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel}"
|
||||
QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -nic user,model=virtio -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel}"
|
||||
|
||||
QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d -monitor ${QEMU_MONITOR} -d ${qemu_trace_std} "
|
||||
|
||||
@ -42,13 +42,13 @@ if [ $flag_can_run -eq 1 ]; then
|
||||
case "$2" in
|
||||
uefi) #uefi启动新增ovmf.fd固件
|
||||
if [ ${ARCH} == x86_64 ] ;then
|
||||
${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}
|
||||
sudo ${QEMU} -bios arch/x86_64/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}
|
||||
elif [ ${ARCH} == i386 ] ;then
|
||||
${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}
|
||||
sudo ${QEMU} -bios arch/i386/efi/OVMF-pure-efi.fd ${QEMU_ARGUMENT}
|
||||
fi
|
||||
;;
|
||||
legacy)
|
||||
${QEMU} ${QEMU_ARGUMENT}
|
||||
sudo ${QEMU} ${QEMU_ARGUMENT}
|
||||
;;
|
||||
esac
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user