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

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
lib.rs 12 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Zhang Bo Отправлено 3 лет назад 3d0e262
// 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.
pub mod errors {
use error_chain::error_chain;
error_chain! {
links {
AddressSpace(address_space::errors::Error, address_space::errors::ErrorKind);
}
errors {
AddPciCap(id: u8, size: usize) {
display("Failed to add PCI capability: id 0x{:x}, size: 0x{:x}.", id, size)
}
AddPcieExtCap(id: u16, size: usize) {
display("Failed to add PCIe extended capability: id 0x{:x}, size: 0x{:x}.", id, size)
}
UnregMemBar(id: usize) {
display("Failed to unmap BAR {} in memory space.", id)
}
DeviceStatus(status: u32) {
display("Invalid device status 0x{:x}", status)
}
PciRegister(offset: u64) {
display("Unsupported pci register, 0x{:x}", offset)
}
}
}
}
pub mod config;
pub mod hotplug;
pub mod msix;
mod bus;
mod host;
mod root_port;
pub use bus::PciBus;
pub use host::PciHost;
pub use msix::init_msix;
pub use root_port::RootPort;
use std::{
mem::size_of,
sync::{Arc, Mutex, Weak},
};
use byteorder::{ByteOrder, LittleEndian};
use error_chain::bail;
use crate::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC};
use crate::errors::Result;
const BDF_FUNC_SHIFT: u8 = 3;
/// Macros that write data in little endian.
macro_rules! le_write {
($name: ident, $func: ident, $type: tt) => {
pub fn $name(buf: &mut [u8], offset: usize, data: $type) -> Result<()> {
let data_len: usize = size_of::<$type>();
let buf_len: usize = buf.len();
if offset + data_len > buf_len {
bail!(
"Out-of-bounds write access: buf_len = {}, offset = {}, data_len = {}",
buf_len,
offset,
data_len
);
}
LittleEndian::$func(&mut buf[offset..(offset + data_len)], data);
Ok(())
}
};
}
le_write!(le_write_u16, write_u16, u16);
le_write!(le_write_u32, write_u32, u32);
le_write!(le_write_u64, write_u64, u64);
/// Macros that read data in little endian.
macro_rules! le_read {
($name: ident, $func: ident, $type: tt) => {
pub fn $name(buf: &[u8], offset: usize) -> Result<$type> {
let data_len: usize = size_of::<$type>();
let buf_len: usize = buf.len();
if offset + data_len > buf_len {
bail!(
"Out-of-bounds read access: buf_len = {}, offset = {}, data_len = {}",
buf_len,
offset,
data_len
);
}
Ok(LittleEndian::$func(&buf[offset..(offset + data_len)]))
}
};
}
le_read!(le_read_u16, read_u16, u16);
le_read!(le_read_u32, read_u32, u32);
le_read!(le_read_u64, read_u64, u64);
fn le_write_set_value_u16(buf: &mut [u8], offset: usize, data: u16) -> Result<()> {
let val = le_read_u16(buf, offset)?;
le_write_u16(buf, offset, val | data)
}
fn le_write_clear_value_u16(buf: &mut [u8], offset: usize, data: u16) -> Result<()> {
let val = le_read_u16(buf, offset)?;
le_write_u16(buf, offset, val & !data)
}
fn pci_devfn(slot: u8, func: u8) -> u8 {
((slot & 0x1f) << 3) | (func & 0x07)
}
fn pci_slot(devfn: u8) -> u8 {
devfn >> 3 & 0x1f
}
fn pci_func(devfn: u8) -> u8 {
devfn & 0x07
}
pub fn pci_ext_cap_id(header: u32) -> u16 {
(header & 0xffff) as u16
}
pub fn pci_ext_cap_ver(header: u32) -> u32 {
(header >> 16) & 0xf
}
pub fn pci_ext_cap_next(header: u32) -> usize {
((header >> 20) & 0xffc) as usize
}
pub trait PciDevOps: Send {
/// Init writable bit mask.
fn init_write_mask(&mut self) -> Result<()>;
/// Init write-and-clear bit mask.
fn init_write_clear_mask(&mut self) -> Result<()>;
/// Realize PCI/PCIe device.
fn realize(self) -> Result<()>;
/// Unrealize PCI/PCIe device.
fn unrealize(&mut self) -> Result<()> {
bail!("Unrealize of the pci device is not implemented");
}
/// Configuration space read.
///
/// # Arguments
///
/// * `offset` - Offset in configuration space.
/// * `data` - Data buffer for reading.
fn read_config(&self, offset: usize, data: &mut [u8]);
/// Configuration space write.
///
/// # Arguments
///
/// * `offset` - Offset in configuration space.
/// * `data` - Data to write.
fn write_config(&mut self, offset: usize, data: &[u8]);
/// Set device id to send MSI/MSI-X.
///
/// # Arguments
///
/// * `bus_num` - Bus number.
/// * `devfn` - Slot number << 8 | Function number.
///
/// # Returns
///
/// Device id to send MSI/MSI-X.
fn set_dev_id(&self, bus_num: u8, devfn: u8) -> u16 {
let bus_shift: u16 = 8;
((bus_num as u16) << bus_shift) | (devfn as u16)
}
/// Get device name.
fn name(&self) -> String;
/// Reset device
fn reset(&mut self, _reset_child_device: bool) -> Result<()> {
Ok(())
}
/// Get device devfn
fn devfn(&self) -> Option<u8> {
None
}
/// Get the path of the PCI bus where the device resides.
fn get_parent_dev_path(&self, parent_bus: Arc<Mutex<PciBus>>) -> String {
let locked_parent_bus = parent_bus.lock().unwrap();
let parent_dev_path = if locked_parent_bus.name.eq("pcie.0") {
String::from("/pci@ffffffffffffffff")
} else {
// This else branch will not be executed currently,
// which is mainly to be compatible with new PCI bridge devices.
// unwrap is safe because pci bus under root port will not return null.
locked_parent_bus
.parent_bridge
.as_ref()
.unwrap()
.upgrade()
.unwrap()
.lock()
.unwrap()
.get_dev_path()
.unwrap()
};
parent_dev_path
}
/// Fill the device patch accroding to parent device patch and device function.
fn populate_dev_path(&self, parent_dev_path: String, devfn: u8, dev_type: &str) -> String {
let mut dev_path = parent_dev_path;
dev_path.push_str(dev_type);
let slot = pci_slot(devfn);
dev_path.push_str(&slot.to_string());
let function = pci_func(devfn);
if function != 0 {
dev_path.push(',');
dev_path.push_str(&function.to_string());
}
dev_path
}
/// Get firmware device path.
fn get_dev_path(&self) -> Option<String> {
None
}
}
/// Init multifunction for pci devices.
///
/// # Arguments
///
/// * `multifunction` - Whether to open multifunction.
/// * `config` - Configuration space of pci devices.
/// * `devfn` - Devfn number.
/// * `parent_bus` - Parent bus of pci devices.
pub fn init_multifunction(
multifunction: bool,
config: &mut [u8],
devfn: u8,
parent_bus: Weak<Mutex<PciBus>>,
) -> Result<()> {
let mut header_type =
le_read_u16(config, HEADER_TYPE as usize)? & (!HEADER_TYPE_MULTIFUNC as u16);
if multifunction {
header_type |= HEADER_TYPE_MULTIFUNC as u16;
}
le_write_u16(config, HEADER_TYPE as usize, header_type as u16)?;
// Allow two ways of multifunction bit:
// 1. The multifunction bit of all devices must be set;
// 2. Function 0 must set the bit, the rest function (1~7) is allowed to
// leave the bit to 0.
let slot = pci_slot(devfn);
let bus = parent_bus.upgrade().unwrap();
let locked_bus = bus.lock().unwrap();
if pci_func(devfn) != 0 {
let pci_dev = locked_bus.devices.get(&pci_devfn(slot, 0));
if pci_dev.is_none() {
return Ok(());
}
let mut data = vec![0_u8; 2];
pci_dev
.unwrap()
.lock()
.unwrap()
.read_config(HEADER_TYPE as usize, data.as_mut_slice());
if LittleEndian::read_u16(&data) & HEADER_TYPE_MULTIFUNC as u16 == 0 {
// Function 0 should set multifunction bit.
bail!(
"PCI: single function device can't be populated in bus {} function {}.{}",
&locked_bus.name,
slot,
devfn & 0x07
);
}
return Ok(());
}
if multifunction {
return Ok(());
}
// If function 0 is set to single function, the rest function should be None.
for func in 1..MAX_FUNC {
if locked_bus.devices.get(&pci_devfn(slot, func)).is_some() {
bail!(
"PCI: {}.0 indicates single function, but {}.{} is already populated",
slot,
slot,
func
);
}
}
Ok(())
}
/// Check whether two regions overlap with each other.
///
/// # Arguments
///
/// * `start` - Start address of the first region.
/// * `end` - End address of the first region.
/// * `region_start` - Start address of the second region.
/// * `region_end` - End address of the second region.
pub fn ranges_overlap(start: usize, end: usize, range_start: usize, range_end: usize) -> bool {
if start >= range_end || range_start >= end {
return false;
}
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_le_write_u16_01() {
let mut buf: [u8; 2] = [0; 2];
le_write_u16(&mut buf, 0, 0x1234_u16).unwrap();
assert_eq!(buf, [0x34, 0x12]);
}
#[test]
fn test_le_write_u16_02() {
let mut buf: [u8; 2] = [0; 2];
assert!(le_write_u16(&mut buf, 1, 0x1234).is_err());
}
#[test]
fn test_le_write_u32_01() {
let mut buf: [u8; 4] = [0; 4];
le_write_u32(&mut buf, 0, 0x1234_5678_u32).unwrap();
assert_eq!(buf, [0x78, 0x56, 0x34, 0x12]);
}
#[test]
fn test_le_write_u32_02() {
let mut buf: [u8; 4] = [0; 4];
assert!(le_write_u32(&mut buf, 1, 0x1234_5678_u32).is_err());
}
#[test]
fn test_le_write_u64_01() {
let mut buf: [u8; 8] = [0; 8];
le_write_u64(&mut buf, 0, 0x1234_5678_9abc_deff).unwrap();
assert_eq!(buf, [0xff, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12]);
}
#[test]
fn test_le_write_u64_02() {
let mut buf: [u8; 8] = [0; 8];
assert!(le_write_u64(&mut buf, 1, 0x1234_5678_9abc_deff).is_err());
}
#[test]
fn test_ranges_overlap() {
assert!(ranges_overlap(100, 200, 150, 250));
assert!(ranges_overlap(100, 200, 150, 200));
assert!(!ranges_overlap(100, 200, 200, 250));
assert!(ranges_overlap(100, 200, 100, 150));
assert!(!ranges_overlap(100, 200, 50, 100));
assert!(ranges_overlap(100, 200, 50, 150));
}
#[test]
fn set_dev_id() {
struct PciDev {
name: String,
}
impl PciDevOps for PciDev {
fn init_write_mask(&mut self) -> Result<()> {
Ok(())
}
fn init_write_clear_mask(&mut self) -> Result<()> {
Ok(())
}
fn read_config(&self, _offset: usize, _data: &mut [u8]) {}
fn write_config(&mut self, _offset: usize, _data: &[u8]) {}
fn name(&self) -> String {
self.name.clone()
}
fn realize(self) -> Result<()> {
Ok(())
}
}
let dev = PciDev {
name: "PCI device".to_string(),
};
assert_eq!(dev.set_dev_id(1, 2), 258);
}
}

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

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

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