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

OSCHINA-MIRROR/openeuler-stratovirt

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
host.rs 28 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Jinhao Gao Отправлено год назад 3b1f985
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
// 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 anyhow::{Context, Result};
#[cfg(target_arch = "aarch64")]
use crate::pci::PCI_INTR_BASE;
use crate::pci::{bus::PciBus, PciDevOps, PCI_PIN_NUM, PCI_SLOT_MAX};
#[cfg(target_arch = "x86_64")]
use crate::pci::{le_read_u32, le_write_u32};
use crate::sysbus::{SysBusDevBase, SysBusDevOps};
use crate::{Device, DeviceBase};
use acpi::{
AmlActiveLevel, AmlAddressSpaceDecode, AmlAnd, AmlArg, AmlBuilder, AmlCacheable,
AmlCreateDWordField, AmlDWord, AmlDWordDesc, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlElse,
AmlEqual, AmlExtendedInterrupt, AmlISARanges, AmlIf, AmlIntShare, AmlInteger, AmlLNot,
AmlLocal, AmlMethod, AmlName, AmlNameDecl, AmlOr, AmlPackage, AmlReadAndWrite, AmlResTemplate,
AmlResourceUsage, AmlReturn, AmlScopeBuilder, AmlStore, AmlString, AmlToUuid, AmlWordDesc,
AmlZero,
};
#[cfg(target_arch = "x86_64")]
use acpi::{AmlIoDecode, AmlIoResource};
#[cfg(target_arch = "aarch64")]
use acpi::{AmlOne, AmlQWordDesc};
use address_space::{AddressSpace, GuestAddress, RegionOps};
#[cfg(target_arch = "x86_64")]
const CONFIG_ADDRESS_ENABLE_MASK: u32 = 0x8000_0000;
#[cfg(target_arch = "x86_64")]
const PIO_BUS_SHIFT: u32 = 16;
#[cfg(target_arch = "x86_64")]
const PIO_DEVFN_SHIFT: u32 = 8;
#[cfg(target_arch = "x86_64")]
const PIO_OFFSET_MASK: u32 = 0xff;
const CONFIG_BUS_MASK: u32 = 0xff;
const CONFIG_DEVFN_MASK: u32 = 0xff;
const ECAM_BUS_SHIFT: u32 = 20;
const ECAM_DEVFN_SHIFT: u32 = 12;
const ECAM_OFFSET_MASK: u64 = 0xfff;
#[derive(Clone)]
pub struct PciHost {
base: SysBusDevBase,
pub root_bus: Arc<Mutex<PciBus>>,
#[cfg(target_arch = "x86_64")]
config_addr: u32,
pcie_ecam_range: (u64, u64),
pcie_mmio_range: (u64, u64),
#[cfg(target_arch = "aarch64")]
pcie_pio_range: (u64, u64),
#[cfg(target_arch = "aarch64")]
high_pcie_mmio_range: (u64, u64),
pub intx_gsi_base: i32,
}
impl PciHost {
/// Construct PCI/PCIe host.
///
/// # Arguments
///
/// * `sys_io` - IO space which the host bridge maps (only on x86_64).
/// * `sys_mem`- Memory space which the host bridge maps.
/// * `pcie_ecam_range` - PCIe ECAM base address and length.
/// * `pcie_mmio_range` - PCIe MMIO base address and length.
/// * `pcie_pio_range` - PCIe PIO base addreass and length (only on aarch64).
/// * `high_pcie_mmio_range` - PCIe high MMIO base address and length (only on aarch64).
/// * `intx_gsi_base` - PCIe INTx gsi base.
pub fn new(
#[cfg(target_arch = "x86_64")] sys_io: &Arc<AddressSpace>,
sys_mem: &Arc<AddressSpace>,
pcie_ecam_range: (u64, u64),
pcie_mmio_range: (u64, u64),
#[cfg(target_arch = "aarch64")] pcie_pio_range: (u64, u64),
#[cfg(target_arch = "aarch64")] high_pcie_mmio_range: (u64, u64),
intx_gsi_base: i32,
) -> Self {
#[cfg(target_arch = "x86_64")]
let io_region = sys_io.root().clone();
let mem_region = sys_mem.root().clone();
let root_bus = PciBus::new(
"pcie.0".to_string(),
#[cfg(target_arch = "x86_64")]
io_region,
mem_region,
);
PciHost {
base: SysBusDevBase::default(),
root_bus: Arc::new(Mutex::new(root_bus)),
#[cfg(target_arch = "x86_64")]
config_addr: 0,
pcie_ecam_range,
pcie_mmio_range,
#[cfg(target_arch = "aarch64")]
pcie_pio_range,
#[cfg(target_arch = "aarch64")]
high_pcie_mmio_range,
intx_gsi_base,
}
}
pub fn find_device(&self, bus_num: u8, devfn: u8) -> Option<Arc<Mutex<dyn PciDevOps>>> {
let locked_root_bus = self.root_bus.lock().unwrap();
if bus_num == 0 {
return locked_root_bus.get_device(0, devfn);
}
for bus in &locked_root_bus.child_buses {
if let Some(b) = PciBus::find_bus_by_num(bus, bus_num) {
return b.lock().unwrap().get_device(bus_num, devfn);
}
}
None
}
/// Build RegionOps for configuration space access by mmconfig.
///
/// # Arguments
///
/// * `host_bridge` - Host brdige device.
pub fn build_mmconfig_ops(host_bridge: Arc<Mutex<Self>>) -> RegionOps {
let cloned_hb = host_bridge.clone();
let read = move |data: &mut [u8], addr: GuestAddress, offset: u64| -> bool {
cloned_hb.lock().unwrap().read(data, addr, offset)
};
let write = move |data: &[u8], addr: GuestAddress, offset: u64| {
host_bridge.lock().unwrap().write(data, addr, offset)
};
RegionOps {
read: Arc::new(read),
write: Arc::new(write),
}
}
/// Build RegionOps for access at 0xCF8.
///
/// # Arguments
///
/// * `host_bridge` - Host brdige device.
#[cfg(target_arch = "x86_64")]
pub fn build_pio_addr_ops(host_bridge: Arc<Mutex<Self>>) -> RegionOps {
let cloned_hb = host_bridge.clone();
let read = move |data: &mut [u8], _addr: GuestAddress, offset: u64| -> bool {
if offset != 0 || data.len() != 4 {
return true;
}
le_write_u32(data, 0, cloned_hb.lock().unwrap().config_addr).unwrap();
true
};
let write = move |data: &[u8], _addr: GuestAddress, offset: u64| -> bool {
if offset != 0 || data.len() != 4 {
return true;
}
host_bridge.lock().unwrap().config_addr = le_read_u32(data, 0).unwrap();
true
};
RegionOps {
read: Arc::new(read),
write: Arc::new(write),
}
}
/// Build RegionOps for access at 0xCFC.
///
/// # Arguments
///
/// * `host_bridge` - Host brdige device.
#[cfg(target_arch = "x86_64")]
pub fn build_pio_data_ops(host_bridge: Arc<Mutex<Self>>) -> RegionOps {
let cloned_hb = host_bridge.clone();
let read = move |data: &mut [u8], _addr: GuestAddress, offset: u64| -> bool {
let locked_hb = cloned_hb.lock().unwrap();
let buf_size = data.len();
if buf_size > 4 || locked_hb.config_addr & CONFIG_ADDRESS_ENABLE_MASK == 0 {
for d in data.iter_mut() {
*d = 0xff;
}
return true;
}
let mut offset: u32 =
(locked_hb.config_addr & !CONFIG_ADDRESS_ENABLE_MASK) + offset as u32;
let bus_num = ((offset >> PIO_BUS_SHIFT) & CONFIG_BUS_MASK) as u8;
let devfn = ((offset >> PIO_DEVFN_SHIFT) & CONFIG_DEVFN_MASK) as u8;
match locked_hb.find_device(bus_num, devfn) {
Some(dev) => {
offset &= PIO_OFFSET_MASK;
dev.lock().unwrap().read_config(offset as usize, data);
}
None => {
for d in data.iter_mut() {
*d = 0xff;
}
}
}
true
};
let write = move |data: &[u8], _addr: GuestAddress, offset: u64| -> bool {
let locked_hb = host_bridge.lock().unwrap();
if data.len() > 4 || locked_hb.config_addr & CONFIG_ADDRESS_ENABLE_MASK == 0 {
return true;
}
let mut offset: u32 =
(locked_hb.config_addr & !CONFIG_ADDRESS_ENABLE_MASK) + offset as u32;
let bus_num = ((offset >> PIO_BUS_SHIFT) & CONFIG_BUS_MASK) as u8;
let devfn = ((offset >> PIO_DEVFN_SHIFT) & CONFIG_DEVFN_MASK) as u8;
if let Some(dev) = locked_hb.find_device(bus_num, devfn) {
offset &= PIO_OFFSET_MASK;
dev.lock().unwrap().write_config(offset as usize, data);
}
true
};
RegionOps {
read: Arc::new(read),
write: Arc::new(write),
}
}
}
impl Device for PciHost {
fn device_base(&self) -> &DeviceBase {
&self.base.base
}
fn device_base_mut(&mut self) -> &mut DeviceBase {
&mut self.base.base
}
}
impl SysBusDevOps for PciHost {
fn sysbusdev_base(&self) -> &SysBusDevBase {
&self.base
}
fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase {
&mut self.base
}
fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool {
let bus_num = ((offset as u32 >> ECAM_BUS_SHIFT) & CONFIG_BUS_MASK) as u8;
let devfn = ((offset as u32 >> ECAM_DEVFN_SHIFT) & CONFIG_DEVFN_MASK) as u8;
match self.find_device(bus_num, devfn) {
Some(dev) => {
let addr: usize = (offset & ECAM_OFFSET_MASK) as usize;
let dev_name = &dev.lock().unwrap().pci_base().base.id.clone();
trace::pci_read_config(dev_name, addr, data);
dev.lock().unwrap().read_config(addr, data);
}
None => {
for d in data.iter_mut() {
*d = 0xff;
}
}
}
true
}
fn write(&mut self, data: &[u8], _base: GuestAddress, offset: u64) -> bool {
let bus_num = ((offset as u32 >> ECAM_BUS_SHIFT) & CONFIG_BUS_MASK) as u8;
let devfn = ((offset as u32 >> ECAM_DEVFN_SHIFT) & CONFIG_DEVFN_MASK) as u8;
match self.find_device(bus_num, devfn) {
Some(dev) => {
let addr: usize = (offset & ECAM_OFFSET_MASK) as usize;
let dev_name = &dev.lock().unwrap().pci_base().base.id.clone();
trace::pci_write_config(dev_name, addr, data);
dev.lock().unwrap().write_config(addr, data);
true
}
None => true,
}
}
fn reset(&mut self) -> Result<()> {
for (_id, pci_dev) in self.root_bus.lock().unwrap().devices.iter_mut() {
pci_dev
.lock()
.unwrap()
.reset(true)
.with_context(|| "Fail to reset pci device under pci host")?;
}
Ok(())
}
}
#[cfg(target_arch = "x86_64")]
fn build_osc_for_aml(pci_host_bridge: &mut AmlDevice) {
let mut method = AmlMethod::new("_OSC", 4, false);
method.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(0), "CDW1"));
let mut if_obj_0 = AmlIf::new(AmlEqual::new(
AmlArg(0),
AmlToUuid::new("33db4d5b-1ff7-401c-9657-7441c03dd766"),
));
if_obj_0.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(4), "CDW2"));
if_obj_0.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(8), "CDW3"));
let cdw3 = AmlName("CDW3".to_string());
if_obj_0.append_child(AmlStore::new(cdw3.clone(), AmlLocal(0)));
// Hotplug: We now support PCIe native hotplug(bit 0) with PCI Express Capability
// Structure(bit 4), other bits: bit1: SHPC; bit2: PME; bit3: AER.
if_obj_0.append_child(AmlAnd::new(AmlLocal(0), AmlInteger(0x11), AmlLocal(0)));
let mut if_obj_1 = AmlIf::new(AmlLNot::new(AmlEqual::new(AmlArg(1), AmlInteger(1))));
let cdw1 = AmlName("CDW1".to_string());
if_obj_1.append_child(AmlOr::new(cdw1.clone(), AmlInteger(0x08), cdw1.clone()));
if_obj_0.append_child(if_obj_1);
let mut if_obj_2 = AmlIf::new(AmlLNot::new(AmlEqual::new(cdw3.clone(), AmlLocal(0))));
if_obj_2.append_child(AmlOr::new(cdw1.clone(), AmlInteger(0x10), cdw1.clone()));
if_obj_0.append_child(if_obj_2);
if_obj_0.append_child(AmlStore::new(AmlLocal(0), cdw3));
method.append_child(if_obj_0);
let mut else_obj_0 = AmlElse::new();
else_obj_0.append_child(AmlOr::new(cdw1.clone(), AmlInteger(0x04), cdw1));
method.append_child(else_obj_0);
method.append_child(AmlReturn::with_value(AmlArg(3)));
pci_host_bridge.append_child(method);
}
#[cfg(target_arch = "aarch64")]
fn build_osc_for_aml(pci_host_bridge: &mut AmlDevice) {
// _OSC means Operating System Capabilities.
pci_host_bridge.append_child(AmlNameDecl::new("SUPP", AmlInteger(0)));
pci_host_bridge.append_child(AmlNameDecl::new("CTRL", AmlInteger(0)));
let mut method = AmlMethod::new("_OSC", 4, false);
method.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(0), "CDW1"));
// The id is for PCI Host Bridge Device.
let mut if_obj_0 = AmlIf::new(AmlEqual::new(
AmlArg(0),
AmlToUuid::new("33db4d5b-1ff7-401c-9657-7441c03dd766"),
));
// Get value from argument for SUPP and CTRL.
if_obj_0.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(4), "CDW2"));
if_obj_0.append_child(AmlCreateDWordField::new(AmlArg(3), AmlInteger(8), "CDW3"));
if_obj_0.append_child(AmlStore::new(
AmlName("CDW2".to_string()),
AmlName("SUPP".to_string()),
));
if_obj_0.append_child(AmlStore::new(
AmlName("CDW3".to_string()),
AmlName("CTRL".to_string()),
));
// Hotplug: We now support PCIe native hotplug(bit 0) with PCI Express Capability
// Structure(bit4), other bits: bit1: SHPC; bit2: PME; bit3: AER.
if_obj_0.append_child(AmlStore::new(
AmlAnd::new(AmlName("CTRL".to_string()), AmlInteger(0x11), AmlLocal(0)),
AmlName("CTRL".to_string()),
));
let mut if_obj_1 = AmlIf::new(AmlLNot::new(AmlEqual::new(AmlArg(1), AmlInteger(1))));
if_obj_1.append_child(AmlAnd::new(
AmlName("CDW1".to_string()),
AmlInteger(0x08),
AmlName("CDW1".to_string()),
));
if_obj_0.append_child(if_obj_1);
let mut if_obj_2 = AmlIf::new(AmlLNot::new(AmlEqual::new(
AmlName("CDW3".to_string()),
AmlName("CTRL".to_string()),
)));
if_obj_2.append_child(AmlOr::new(
AmlName("CDW1".to_string()),
AmlInteger(0x10),
AmlName("CDW1".to_string()),
));
if_obj_0.append_child(if_obj_2);
if_obj_0.append_child(AmlStore::new(
AmlName("CTRL".to_string()),
AmlName("CDW3".to_string()),
));
// For pci host, kernel will use _OSC return value to determine whether
// native_pcie_hotplug is enabled or not.
if_obj_0.append_child(AmlReturn::with_value(AmlArg(3)));
method.append_child(if_obj_0);
let mut else_obj_0 = AmlElse::new();
else_obj_0.append_child(AmlOr::new(
AmlName("CDW1".to_string()),
AmlInteger(0x04),
AmlName("CDW1".to_string()),
));
else_obj_0.append_child(AmlReturn::with_value(AmlArg(3)));
method.append_child(else_obj_0);
pci_host_bridge.append_child(method);
}
fn build_prt_for_aml(pci_bus: &mut AmlDevice, irq: i32) {
let mut prt_pkg = AmlPackage::new(PCI_SLOT_MAX * PCI_PIN_NUM);
(0..PCI_SLOT_MAX).for_each(|slot| {
(0..PCI_PIN_NUM).for_each(|pin| {
let gsi = (pin + slot) % PCI_PIN_NUM;
let mut pkg = AmlPackage::new(4);
pkg.append_child(AmlDWord((slot as u32) << 16 | 0xFFFF));
pkg.append_child(AmlDWord(pin as u32));
pkg.append_child(AmlName(format!("GSI{}", gsi)));
pkg.append_child(AmlZero);
prt_pkg.append_child(pkg);
});
});
pci_bus.append_child(AmlNameDecl::new("_PRT", prt_pkg));
for i in 0..PCI_PIN_NUM {
#[cfg(target_arch = "x86_64")]
let irqs = irq as u8 + i;
#[cfg(target_arch = "aarch64")]
let irqs = irq as u8 + PCI_INTR_BASE + i;
let mut gsi = AmlDevice::new(format!("GSI{}", i).as_str());
gsi.append_child(AmlNameDecl::new("_HID", AmlEisaId::new("PNP0C0F")));
gsi.append_child(AmlNameDecl::new("_UID", AmlString(i.to_string())));
let mut crs = AmlResTemplate::new();
crs.append_child(AmlExtendedInterrupt::new(
AmlResourceUsage::Consumer,
AmlEdgeLevel::Level,
AmlActiveLevel::High,
AmlIntShare::Exclusive,
vec![irqs as u32],
));
gsi.append_child(AmlNameDecl::new("_PRS", crs));
let mut crs = AmlResTemplate::new();
crs.append_child(AmlExtendedInterrupt::new(
AmlResourceUsage::Consumer,
AmlEdgeLevel::Level,
AmlActiveLevel::High,
AmlIntShare::Exclusive,
vec![irqs as u32],
));
gsi.append_child(AmlNameDecl::new("_CRS", crs));
let method = AmlMethod::new("_SRS", 1, false);
gsi.append_child(method);
pci_bus.append_child(gsi);
}
}
impl AmlBuilder for PciHost {
fn aml_bytes(&self) -> Vec<u8> {
let mut pci_host_bridge = AmlDevice::new("PCI0");
pci_host_bridge.append_child(AmlNameDecl::new("_HID", AmlEisaId::new("PNP0A08")));
pci_host_bridge.append_child(AmlNameDecl::new("_CID", AmlEisaId::new("PNP0A03")));
pci_host_bridge.append_child(AmlNameDecl::new("_ADR", AmlZero));
pci_host_bridge.append_child(AmlNameDecl::new("_UID", AmlZero));
#[cfg(target_arch = "aarch64")]
{
// CCA: Cache Coherency Attribute, which determines whether
// guest supports DMA features in pci host on aarch64 platform.
pci_host_bridge.append_child(AmlNameDecl::new("_CCA", AmlOne));
// SEG: The PCI segment number.
pci_host_bridge.append_child(AmlNameDecl::new("_SEG", AmlZero));
}
build_osc_for_aml(&mut pci_host_bridge);
let pcie_ecam = self.pcie_ecam_range;
let pcie_mmio = self.pcie_mmio_range;
// Build and append "\_SB.PCI0._CRS" to PCI host bridge node.
let max_nr_bus = (pcie_ecam.1 >> 20) as u16;
let mut crs = AmlResTemplate::new();
crs.append_child(AmlWordDesc::new_bus_number(
AmlAddressSpaceDecode::Positive,
0,
0,
max_nr_bus - 1,
0,
max_nr_bus,
));
#[cfg(target_arch = "x86_64")]
{
crs.append_child(AmlIoResource::new(
AmlIoDecode::Decode16,
0xcf8,
0xcf8,
1,
8,
));
crs.append_child(AmlWordDesc::new_io(
AmlAddressSpaceDecode::Positive,
AmlISARanges::EntireRange,
0,
0,
0x0cf7,
0,
0xcf8,
));
crs.append_child(AmlWordDesc::new_io(
AmlAddressSpaceDecode::Positive,
AmlISARanges::EntireRange,
0,
0x0d00,
0xffff,
0,
0xf300,
));
}
#[cfg(target_arch = "aarch64")]
{
let pcie_pio = self.pcie_pio_range;
crs.append_child(AmlDWordDesc::new_io(
AmlAddressSpaceDecode::Positive,
AmlISARanges::EntireRange,
0,
pcie_pio.0 as u32,
(pcie_pio.0 + pcie_pio.1) as u32 - 1,
0,
pcie_pio.1 as u32,
));
let high_pcie_mmio = self.high_pcie_mmio_range;
crs.append_child(AmlQWordDesc::new_memory(
AmlAddressSpaceDecode::Positive,
AmlCacheable::NonCacheable,
AmlReadAndWrite::ReadWrite,
0,
high_pcie_mmio.0,
high_pcie_mmio.0 + high_pcie_mmio.1 - 1,
0,
high_pcie_mmio.1,
));
}
crs.append_child(AmlDWordDesc::new_memory(
AmlAddressSpaceDecode::Positive,
AmlCacheable::NonCacheable,
AmlReadAndWrite::ReadWrite,
0,
pcie_mmio.0 as u32,
(pcie_mmio.0 + pcie_mmio.1) as u32 - 1,
0,
pcie_mmio.1 as u32,
));
pci_host_bridge.append_child(AmlNameDecl::new("_CRS", crs));
build_prt_for_aml(&mut pci_host_bridge, self.intx_gsi_base);
pci_host_bridge.aml_bytes()
}
}
#[cfg(test)]
pub mod tests {
use byteorder::{ByteOrder, LittleEndian};
use super::*;
use crate::pci::bus::PciBus;
use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE, SECONDARY_BUS_NUM};
use crate::pci::root_port::RootPort;
use crate::pci::{PciDevBase, Result};
use crate::{Device, DeviceBase};
use address_space::Region;
struct PciDevice {
base: PciDevBase,
}
impl Device for PciDevice {
fn device_base(&self) -> &DeviceBase {
&self.base.base
}
fn device_base_mut(&mut self) -> &mut DeviceBase {
&mut self.base.base
}
}
impl PciDevOps for PciDevice {
fn pci_base(&self) -> &PciDevBase {
&self.base
}
fn pci_base_mut(&mut self) -> &mut PciDevBase {
&mut self.base
}
fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> {
let mut offset = 0_usize;
while offset < self.base.config.config.len() {
LittleEndian::write_u32(
&mut self.base.config.write_mask[offset..offset + 4],
0xffff_ffff,
);
offset += 4;
}
Ok(())
}
fn init_write_clear_mask(&mut self, _is_bridge: bool) -> Result<()> {
Ok(())
}
fn write_config(&mut self, offset: usize, data: &[u8]) {
#[allow(unused_variables)]
self.base.config.write(
offset,
data,
0,
#[cfg(target_arch = "x86_64")]
None,
None,
);
}
fn realize(mut self) -> Result<()> {
let devfn = self.base.devfn;
self.init_write_mask(false)?;
self.init_write_clear_mask(false)?;
let dev = Arc::new(Mutex::new(self));
dev.lock()
.unwrap()
.base
.parent_bus
.upgrade()
.unwrap()
.lock()
.unwrap()
.devices
.insert(devfn, dev.clone());
Ok(())
}
}
pub fn create_pci_host() -> Arc<Mutex<PciHost>> {
#[cfg(target_arch = "x86_64")]
let sys_io = AddressSpace::new(
Region::init_container_region(1 << 16, "sysio"),
"sysio",
None,
)
.unwrap();
let sys_mem = AddressSpace::new(
Region::init_container_region(u64::max_value(), "sysmem"),
"sysmem",
None,
)
.unwrap();
Arc::new(Mutex::new(PciHost::new(
#[cfg(target_arch = "x86_64")]
&sys_io,
&sys_mem,
(0xB000_0000, 0x1000_0000),
(0xC000_0000, 0x3000_0000),
#[cfg(target_arch = "aarch64")]
(0xF000_0000, 0x1000_0000),
#[cfg(target_arch = "aarch64")]
(512 << 30, 512 << 30),
16,
)))
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_pio_ops() {
let pci_host = create_pci_host();
let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus);
let pio_addr_ops = PciHost::build_pio_addr_ops(pci_host.clone());
let pio_data_ops = PciHost::build_pio_data_ops(pci_host.clone());
let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false);
root_port.realize().unwrap();
let mut data = [0_u8; 4];
let addr: u32 = CONFIG_ADDRESS_ENABLE_MASK | 8 << PIO_DEVFN_SHIFT | 0x28;
LittleEndian::write_u32(&mut data, addr);
(pio_addr_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, data);
let data = [1_u8; 4];
(pio_data_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_data_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, data);
// Non-DWORD access on CONFIG_ADDR
let mut config = [0_u8; 4];
(pio_addr_ops.read)(&mut config, GuestAddress(0), 0);
let data = [0x12, 0x34];
(pio_addr_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, config);
let data = [0x12, 0x34, 0x56, 0x78];
(pio_addr_ops.write)(&data, GuestAddress(0), 1);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, config);
let mut buf = [0_u8; 2];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, [0_u8; 2]);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 1);
assert_eq!(buf, [0_u8; 4]);
let mut buf = [0_u8; 5];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, [0_u8; 5]);
// Enable bit of CONFIG_ADDR is not set.
let mut data = [0_u8; 4];
let addr: u32 = 8 << PIO_DEVFN_SHIFT | 16 << 2;
LittleEndian::write_u32(&mut data, addr);
(pio_addr_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, data);
let data = [1_u8; 4];
(pio_data_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_data_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, [0xff_u8; 4]);
// Access non-exist device.
let mut data = [0_u8; 4];
let addr: u32 = 1 << PIO_DEVFN_SHIFT | 16 << 2;
LittleEndian::write_u32(&mut data, addr);
(pio_addr_ops.write)(&data, GuestAddress(0), 0);
let mut buf = [0_u8; 4];
(pio_addr_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, data);
let mut buf = [0_u8; 4];
(pio_data_ops.read)(&mut buf, GuestAddress(0), 0);
assert_eq!(buf, [0xff_u8; 4]);
}
#[test]
fn test_mmio_ops() {
let pci_host = create_pci_host();
let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus);
let mmconfig_region_ops = PciHost::build_mmconfig_ops(pci_host.clone());
let mut root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false);
root_port.write_config(SECONDARY_BUS_NUM as usize, &[1]);
root_port.realize().unwrap();
let mut root_port = RootPort::new("pcie.2".to_string(), 16, 0, root_bus, false);
root_port.write_config(SECONDARY_BUS_NUM as usize, &[2]);
root_port.realize().unwrap();
let bus = PciBus::find_bus_by_name(&pci_host.lock().unwrap().root_bus, "pcie.2").unwrap();
let pci_dev = PciDevice {
base: PciDevBase {
base: DeviceBase::new("PCI device".to_string(), false),
config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0),
devfn: 8,
parent_bus: Arc::downgrade(&bus),
},
};
pci_dev.realize().unwrap();
let addr: u64 = 8_u64 << ECAM_DEVFN_SHIFT | SECONDARY_BUS_NUM as u64;
let data = [1_u8];
(mmconfig_region_ops.write)(&data, GuestAddress(0), addr);
let mut buf = [0_u8];
(mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr);
assert_eq!(buf, data);
let addr: u64 = 16_u64 << ECAM_DEVFN_SHIFT | SECONDARY_BUS_NUM as u64;
let data = [2_u8];
(mmconfig_region_ops.write)(&data, GuestAddress(0), addr);
let mut buf = [0_u8];
(mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr);
assert_eq!(buf, data);
// Access non-exist device.
let addr: u64 = 1 << ECAM_BUS_SHIFT | 16 << ECAM_DEVFN_SHIFT | 2;
let mut buf = [0_u8; 2];
(mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr);
assert_eq!(buf, [0xff_u8; 2]);
let addr: u64 = 2 << ECAM_BUS_SHIFT | 8 << ECAM_DEVFN_SHIFT | 2;
let data = [1_u8; 2];
(mmconfig_region_ops.write)(&data, GuestAddress(0), addr);
let mut buf = [0_u8; 2];
(mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr);
assert_eq!(buf, data);
}
}

Опубликовать ( 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.4.0