1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
bus.rs 15 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Ming Yang Отправлено 4 лет назад 45f135c
// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved.
//
// StratoVirt is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
use std::sync::{Arc, Mutex};
use address_space::AddressSpace;
use kvm_ioctls::VmFd;
use machine_manager::config::{BootSource, ConfigCheck};
use super::super::virtio::{Block, Net};
use super::{
errors::{Result, ResultExt},
DeviceResource, DeviceType, MmioDevice, MmioDeviceOps, VirtioMmioDevice,
};
use crate::{LayoutEntryType, MEM_LAYOUT};
#[cfg(target_arch = "aarch64")]
const IRQ_RANGE: (u32, u32) = (32, 191);
#[cfg(target_arch = "x86_64")]
const IRQ_RANGE: (u32, u32) = (5, 15);
const MMIO_SERIAL_IRQ: u32 = 4;
#[cfg(target_arch = "x86_64")]
const MMIO_SERIAL_ADDR: u64 = 0x3f8;
const MMIO_BASE: u64 = MEM_LAYOUT[LayoutEntryType::Mmio as usize].0;
const MMIO_LEN: u64 = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1;
/// The replaceable block device maximum count.
pub const MMIO_REPLACEABLE_BLK_NR: usize = 6;
/// The replaceable network device maximum count.
pub const MMIO_REPLACEABLE_NET_NR: usize = 2;
/// The config of replaceable device.
struct MmioReplaceableConfig {
/// Device id.
id: String,
/// The dev_config of the related backend device.
dev_config: Arc<dyn ConfigCheck>,
}
/// The device information of replaceable device.
struct MmioReplaceableDevInfo {
/// The related MMIO device.
device: MmioDevice,
/// Device id.
id: String,
/// Identify if this device is be used.
used: bool,
}
/// The gather of config, info and count of all replaceable devices.
struct MmioReplaceableInfo {
/// The arrays of all replaceable configs.
configs: Arc<Mutex<Vec<MmioReplaceableConfig>>>,
/// The arrays of all replaceable device information.
devices: Arc<Mutex<Vec<MmioReplaceableDevInfo>>>,
/// The count of block device which is plugin.
block_count: usize,
/// The count of network device which is plugin.
net_count: usize,
}
impl MmioReplaceableInfo {
pub fn new() -> Self {
MmioReplaceableInfo {
configs: Arc::new(Mutex::new(Vec::new())),
devices: Arc::new(Mutex::new(Vec::new())),
block_count: 0_usize,
net_count: 0_usize,
}
}
}
/// MMIO Bus.
pub struct Bus {
/// The devices inserted in bus.
devices: Vec<MmioDevice>,
/// All replaceable device information.
replaceable_info: MmioReplaceableInfo,
}
impl Bus {
/// Initial the MMIO Bus structure.
///
/// # Steps
///
/// 1. Initial MMIO Bus
/// 2. Prepare the replaceable information of block and network devices.
///
/// # Arguments
///
/// * `sys_mem` - guest memory.
pub fn new(sys_mem: Arc<AddressSpace>) -> Self {
let mut bus = Bus {
devices: Vec::new(),
replaceable_info: MmioReplaceableInfo::new(),
};
for _ in 0..MMIO_REPLACEABLE_BLK_NR {
let block = Arc::new(Mutex::new(Block::new()));
let device = Arc::new(Mutex::new(VirtioMmioDevice::new(sys_mem.clone(), block)));
if let Ok(dev) = bus.attach_device(device.clone()) {
bus.replaceable_info
.devices
.lock()
.unwrap()
.push(MmioReplaceableDevInfo {
device: dev,
id: "".to_string(),
used: false,
});
}
}
for _ in 0..MMIO_REPLACEABLE_NET_NR {
let net = Arc::new(Mutex::new(Net::new()));
let device = Arc::new(Mutex::new(VirtioMmioDevice::new(sys_mem.clone(), net)));
if let Ok(dev) = bus.attach_device(device.clone()) {
bus.replaceable_info
.devices
.lock()
.unwrap()
.push(MmioReplaceableDevInfo {
device: dev,
id: "".to_string(),
used: false,
});
}
}
bus
}
/// Attach a MMIO device to Bus.
///
/// # Arguments
///
/// * `device` - MMIO device.
///
/// # Errors
///
/// Return Error if irq number exceed the limit as Arch spec defined.
pub fn attach_device<T: 'static + MmioDeviceOps>(
&mut self,
device: Arc<Mutex<T>>,
) -> Result<MmioDevice> {
let device_type = device.lock().unwrap().get_type();
let index = self.devices.len();
let resource = match device_type {
#[cfg(target_arch = "aarch64")]
DeviceType::RTC => DeviceResource {
addr: MEM_LAYOUT[LayoutEntryType::Rtc as usize].0,
size: MEM_LAYOUT[LayoutEntryType::Rtc as usize].1,
irq: IRQ_RANGE.0 + index as u32,
dev_type: device_type,
},
DeviceType::SERIAL => {
#[cfg(target_arch = "x86_64")]
{
DeviceResource {
addr: MMIO_SERIAL_ADDR,
size: 8,
irq: MMIO_SERIAL_IRQ,
dev_type: device_type,
}
}
#[cfg(target_arch = "aarch64")]
{
DeviceResource {
addr: MEM_LAYOUT[LayoutEntryType::Uart as usize].0,
size: MEM_LAYOUT[LayoutEntryType::Uart as usize].1,
irq: MMIO_SERIAL_IRQ,
dev_type: device_type,
}
}
}
_ => DeviceResource {
addr: MMIO_BASE + index as u64 * MMIO_LEN,
size: MMIO_LEN,
irq: IRQ_RANGE.0 + index as u32,
dev_type: device_type,
},
};
if resource.irq > IRQ_RANGE.1 {
bail!(
"irq {} exceed max value {}, index: {} type: {:?}",
resource.irq,
IRQ_RANGE.1,
index,
device_type
);
}
let mmio_dev = MmioDevice::new(device, resource);
self.devices.push(mmio_dev.clone());
Ok(mmio_dev)
}
/// Get the information of all devices inserted in bus.
#[cfg(target_arch = "aarch64")]
pub fn get_devices_info(&self) -> Vec<DeviceResource> {
let mut infos = Vec::new();
for dev in self.devices.iter() {
infos.push(dev.get_resource())
}
infos
}
/// Get an unused entry of replaceable_info, then fill the fields and mark it as `used`.
///
/// # Arguments
///
/// * `id` - Device id.
/// * `path` - Related backend device path.
/// * `dev_type` - MMIO device type.
///
/// # Errors
///
/// Returns Error if the device number exceed the Max count.
pub fn fill_replaceable_device(
&mut self,
id: &str,
dev_config: Arc<dyn ConfigCheck>,
dev_type: DeviceType,
) -> Result<()> {
let index = match dev_type {
DeviceType::BLK => {
let index = self.replaceable_info.block_count;
if index >= MMIO_REPLACEABLE_BLK_NR {
bail!(
"Index {} is out of bounds {} for block to fill replaceable device",
index,
MMIO_REPLACEABLE_BLK_NR,
);
}
self.replaceable_info.block_count += 1;
index
}
DeviceType::NET => {
let index = self.replaceable_info.net_count + MMIO_REPLACEABLE_BLK_NR;
if index >= MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR {
bail!(
"Index {} is out of bounds {} for net to fill replaceable device",
index,
MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR,
);
}
self.replaceable_info.net_count += 1;
index
}
_ => {
bail!("Unsupported replaceable device type to fill replaceable device, id: {} type: {:?}",
id, dev_type);
}
};
let mut replaceable_devices = self.replaceable_info.devices.lock().unwrap();
if let Some(device_info) = replaceable_devices.get_mut(index) {
if device_info.used {
return Err(format!("The index{} is used, {}", index, id).into());
} else {
device_info.id = id.to_string();
device_info.used = true;
device_info.device.update_config(Some(dev_config.clone()))?;
}
}
self.add_replaceable_config(id.to_string(), dev_config)?;
Ok(())
}
/// Add new config into replaceable_info configs arrays.
///
/// # Arguments
///
/// * `id` - Device id.
/// * `path` - Related backend device path.
pub fn add_replaceable_config(
&self,
id: String,
dev_config: Arc<dyn ConfigCheck>,
) -> Result<()> {
let mut configs_lock = self.replaceable_info.configs.lock().unwrap();
if configs_lock.len() >= MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR {
bail!(
"The size {} of replaceable configs extend the max size {}, id {}.",
configs_lock.len(),
MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR,
id,
);
}
for config in configs_lock.iter() {
if config.id == id {
bail!("Add the id {} repeatedly", id);
}
}
let config = MmioReplaceableConfig { id, dev_config };
configs_lock.push(config);
Ok(())
}
/// Get an unused entry of replaceable_info which is indexed by `slot`,
/// then update the fields and mark it as `used`.
///
/// # Arguments
///
/// * `id` - Device id.
/// * `driver` - Driver type passed in by HotPlug.
/// * `slot` - The index of replaceable_info entries.
///
/// # Errors
///
/// Returns Error if the entry is already used.
pub fn add_replaceable_device(&self, id: &str, driver: &str, slot: usize) -> Result<()> {
let index = if driver.contains("net") {
if slot >= MMIO_REPLACEABLE_NET_NR {
bail!(
"Index {} is out of bounds {} for net to add replaceable device",
slot,
MMIO_REPLACEABLE_NET_NR
);
}
slot + MMIO_REPLACEABLE_BLK_NR
} else if driver.contains("blk") {
if slot >= MMIO_REPLACEABLE_BLK_NR {
bail!(
"Index {} is out of bounds {} for block to add replaceable device",
slot,
MMIO_REPLACEABLE_BLK_NR
);
}
slot
} else {
bail!(
"Unsupported replaceable device type to add replaceable device, id: {} driver: {}",
id,
driver,
);
};
let configs_lock = self.replaceable_info.configs.lock().unwrap();
// find the configuration by id
let mut dev_config = None;
for config in configs_lock.iter() {
if config.id == id {
dev_config = Some(config.dev_config.clone());
}
}
if dev_config.is_none() {
bail!(
"Failed to find the configuration to add replaceable device, id: {} driver: {}",
id,
driver
);
}
// find the replaceable device and replace it
let mut replaceable_devices = self.replaceable_info.devices.lock().unwrap();
if let Some(device_info) = replaceable_devices.get_mut(index) {
if device_info.used {
bail!(
"The slot {} is already used for adding replaceable device, {}",
slot,
id
);
} else {
device_info.id = id.to_string();
device_info.used = true;
device_info.device.update_config(dev_config)?;
}
}
Ok(())
}
/// Find the entry of replaceable_info which is specified by `id`,
/// then update the fields and mark it as `unused`.
///
/// # Arguments
///
/// * `id` - Device id.
pub fn del_replaceable_device(&self, id: &str) -> Result<String> {
// find the index of configuration by name and remove it
let mut is_exist = false;
let mut configs_lock = self.replaceable_info.configs.lock().unwrap();
for (index, config) in configs_lock.iter().enumerate() {
if config.id == id {
configs_lock.remove(index);
is_exist = true;
break;
}
}
// set the status of the device to 'unused'
let mut replaceable_devices = self.replaceable_info.devices.lock().unwrap();
for device_info in replaceable_devices.iter_mut() {
if device_info.id == id {
device_info.id = "".to_string();
device_info.used = false;
device_info.device.update_config(None)?;
}
}
if !is_exist {
bail!("Device {} not found", id);
}
Ok(id.to_string())
}
/// Realize all the devices inserted in this Bus.
///
/// # Arguments
///
/// * `vm_fd` - The file descriptor of VM.
/// * `bs` - The boot source of VM.
/// * `sys_mem` - The guest memory to device constructs over.
pub fn realize_devices(
&self,
vm_fd: &VmFd,
bs: &Arc<Mutex<BootSource>>,
sys_mem: &Arc<AddressSpace>,
#[cfg(target_arch = "x86_64")] sys_io: Arc<AddressSpace>,
) -> Result<()> {
for device in &self.devices {
device
.realize(
vm_fd,
&bs,
&sys_mem,
#[cfg(target_arch = "x86_64")]
sys_io.clone(),
)
.chain_err(|| "Failed to realize mmio device")?;
}
Ok(())
}
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/openeuler-stratovirt.git
git@gitlife.ru:oschina-mirror/openeuler-stratovirt.git
oschina-mirror
openeuler-stratovirt
openeuler-stratovirt
v0.2.0