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:
YJwu2023 2023-03-18 20:43:37 +08:00 committed by GitHub
parent 4454d1a2dd
commit 73c607aadd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 216 additions and 121 deletions

View File

@ -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

View File

@ -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,
);
}

View File

@ -1,4 +1,3 @@
pub mod transport_pci;
pub mod virtio;
pub mod virtio_impl;
pub mod volatile;

View File

@ -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, &notify_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()
}

View File

@ -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();

View File

@ -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");

View File

@ -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
}

View File

@ -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);
}

View File

@ -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> {

View File

@ -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;

View File

@ -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 {

View File

@ -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);
};
}

View File

@ -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