pci: move to .init_array-based driver registration

This commit is contained in:
Mark Poliakov 2025-02-03 14:48:23 +02:00
parent a11956de50
commit 53de6e26dd
16 changed files with 376 additions and 336 deletions

1
Cargo.lock generated
View File

@ -2866,6 +2866,7 @@ dependencies = [
"async-trait",
"bitflags 2.8.0",
"bytemuck",
"cfg-if",
"chrono",
"crossbeam-queue",
"device-api",

View File

@ -45,6 +45,7 @@ bytemuck.workspace = true
futures-util.workspace = true
crossbeam-queue.workspace = true
async-trait.workspace = true
cfg-if.workspace = true
git-version = "0.3.9"

View File

@ -20,6 +20,7 @@ use regs::{PortRegs, Regs};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciCommandRegister, PciConfigurationSpace,
};
use yggdrasil_abi::{error::Error, io::FileMode};
@ -191,51 +192,6 @@ impl Device for AhciController {
}
}
static SATA_DRIVES: IrqSafeSpinlock<Vec<Arc<AhciPort>>> = IrqSafeSpinlock::new(Vec::new());
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let bar5 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?;
let bar5 = bar5.as_memory().ok_or(Error::InvalidOperation)?;
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
// // TODO support regular PCI interrupts (ACPI dependency)
// let Some(mut msi) = info.config_space.capability::<MsiCapability>() else {
// log::warn!("Ignoring AHCI: does not support MSI (and the OS doesn't yet support PCI IRQ)");
// return Err(Error::InvalidOperation);
// };
// Map the registers
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?;
let version = Version::try_from(regs.VS.get())?;
let ahci_only = regs.CAP.matches_all(CAP::SAM::SET);
let max_port_count = regs.CAP.read(CAP::NP) as usize;
let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET);
// TODO extract Number of Command Slots
let ahci = Arc::new(AhciController {
regs: IrqSafeSpinlock::new(regs),
ports: OneTimeInit::new(),
received_fis_buffers: OneTimeInit::new(),
version,
max_port_count,
ahci_only,
has_64_bit,
});
// TODO use multiple vectors if capable
info.map_interrupt(InterruptAffinity::Any, ahci.clone())?;
Ok(ahci)
}
pub fn register_sata_drive(drive: Arc<AhciPort>, probe: bool) {
let index = {
let mut drives = SATA_DRIVES.lock();
@ -273,3 +229,57 @@ pub fn register_sata_drive(drive: Arc<AhciPort>, probe: bool) {
.ok();
}
}
static SATA_DRIVES: IrqSafeSpinlock<Vec<Arc<AhciPort>>> = IrqSafeSpinlock::new(Vec::new());
pci_driver! {
matches: [class (0x01:0x06:0x01)],
driver: {
fn driver_name(&self) -> &str {
"ahci"
}
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let bar5 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?;
let bar5 = bar5.as_memory().ok_or(Error::InvalidOperation)?;
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
// // TODO support regular PCI interrupts (ACPI dependency)
// let Some(mut msi) = info.config_space.capability::<MsiCapability>() else {
// log::warn!("Ignoring AHCI: does not support MSI (and the OS doesn't yet support PCI IRQ)");
// return Err(Error::InvalidOperation);
// };
// Map the registers
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?;
let version = Version::try_from(regs.VS.get())?;
let ahci_only = regs.CAP.matches_all(CAP::SAM::SET);
let max_port_count = regs.CAP.read(CAP::NP) as usize;
let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET);
// TODO extract Number of Command Slots
let ahci = Arc::new(AhciController {
regs: IrqSafeSpinlock::new(regs),
ports: OneTimeInit::new(),
received_fis_buffers: OneTimeInit::new(),
version,
max_port_count,
ahci_only,
has_64_bit,
});
// TODO use multiple vectors if capable
info.map_interrupt(InterruptAffinity::Any, ahci.clone())?;
Ok(ahci)
}
}
}

View File

@ -35,6 +35,7 @@ use tock_registers::{
};
use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciCommandRegister, PciConfigurationSpace,
};
use yggdrasil_abi::{error::Error, io::FileMode};
@ -417,54 +418,6 @@ impl Device for NvmeController {
// TODO
unsafe impl Sync for NvmeController {}
static NVME_CONTROLLERS: IrqSafeSpinlock<Vec<Arc<NvmeController>>> =
IrqSafeSpinlock::new(Vec::new());
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let bar0 = info
.config_space
.bar(0)
.unwrap()
.as_memory()
.expect("Expected a memory BAR0");
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar0, Default::default()) }?;
// Disable the controller
regs.CC.modify(CC::ENABLE::CLEAR);
let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1;
let min_page_size = 1 << (regs.CAP.read(CAP::MPSMIN) + 12);
if min_page_size > PAGE_SIZE {
log::error!("Cannot support NVMe HC: min page size ({min_page_size}) > host page size ({PAGE_SIZE})");
return Err(Error::InvalidArgument);
}
let device = NvmeController {
regs: IrqSafeSpinlock::new(regs),
admin_q: OneTimeInit::new(),
ioqs: OneTimeInit::new(),
drive_table: IrqSafeSpinlock::new(BTreeMap::new()),
controller_id: OneTimeInit::new(),
pci: info.clone(),
io_queue_count: AtomicUsize::new(1),
doorbell_shift,
min_page_size,
};
Ok(Arc::new(device))
}
pub fn register_nvme_controller(controller: Arc<NvmeController>) {
let mut list = NVME_CONTROLLERS.lock();
let id = list.len();
@ -496,3 +449,60 @@ pub fn register_nvme_namespace(namespace: Arc<NvmeNamespace>, probe: bool) {
.ok();
}
}
static NVME_CONTROLLERS: IrqSafeSpinlock<Vec<Arc<NvmeController>>> =
IrqSafeSpinlock::new(Vec::new());
pci_driver! {
matches: [class (0x01:0x08:0x02)],
driver: {
fn driver_name(&self) -> &str {
"nvme"
}
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let bar0 = info
.config_space
.bar(0)
.unwrap()
.as_memory()
.expect("Expected a memory BAR0");
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar0, Default::default()) }?;
// Disable the controller
regs.CC.modify(CC::ENABLE::CLEAR);
let doorbell_shift = regs.CAP.read(CAP::DSTRD) as usize + 1;
let min_page_size = 1 << (regs.CAP.read(CAP::MPSMIN) + 12);
if min_page_size > PAGE_SIZE {
log::error!("Cannot support NVMe HC: min page size ({min_page_size}) > host page size ({PAGE_SIZE})");
return Err(Error::InvalidArgument);
}
let device = NvmeController {
regs: IrqSafeSpinlock::new(regs),
admin_q: OneTimeInit::new(),
ioqs: OneTimeInit::new(),
drive_table: IrqSafeSpinlock::new(BTreeMap::new()),
controller_id: OneTimeInit::new(),
pci: info.clone(),
io_queue_count: AtomicUsize::new(1),
doorbell_shift,
min_page_size,
};
Ok(Arc::new(device))
}
}
}

View File

@ -78,19 +78,6 @@ pub struct PciInterruptRoute {
pub options: IrqOptions,
}
pub enum PciMatch {
Generic(fn(&PciDeviceInfo) -> bool),
Vendor(u16, u16),
Class(u8, Option<u8>, Option<u8>),
}
pub struct PciDriver {
#[allow(unused)]
pub(crate) name: &'static str,
pub(crate) check: PciMatch,
pub(crate) probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
}
/// Used to store PCI bus devices which were enumerated by the kernel
pub struct PciBusDevice {
pub(crate) info: PciDeviceInfo,

View File

@ -0,0 +1,59 @@
use alloc::{sync::Arc, vec::Vec};
use device_api::device::Device;
use libk::error::Error;
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use crate::device::PciDeviceInfo;
pub enum PciMatch {
Generic(fn(&PciDeviceInfo) -> bool),
Vendor(u16, u16),
Class(u8, Option<u8>, Option<u8>),
}
pub struct PciDriverMatch {
pub driver: &'static dyn PciDriver,
pub check: PciMatch,
}
pub trait PciDriver: Sync {
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error>;
fn driver_name(&self) -> &str;
}
impl PciMatch {
pub fn check_device(&self, info: &PciDeviceInfo) -> bool {
match self {
Self::Generic(f) => f(info),
&Self::Vendor(vendor_, device_) => {
info.vendor_id == vendor_ && info.device_id == device_
}
&Self::Class(class_, Some(subclass_), Some(prog_if_)) => {
class_ == info.class && subclass_ == info.subclass && prog_if_ == info.prog_if
}
&Self::Class(class_, Some(subclass_), _) => {
class_ == info.class && subclass_ == info.subclass
}
&Self::Class(class_, _, _) => class_ == info.class,
}
}
}
pub fn register_match(pmatch: PciMatch, driver: &'static dyn PciDriver) {
DRIVERS.write().push(PciDriverMatch {
check: pmatch,
driver,
});
}
pub fn lookup_driver(info: &PciDeviceInfo) -> Option<&'static dyn PciDriver> {
DRIVERS.read().iter().find_map(|pmatch| {
if pmatch.check.check_device(info) {
Some(pmatch.driver)
} else {
None
}
})
}
static DRIVERS: IrqSafeRwLock<Vec<PciDriverMatch>> = IrqSafeRwLock::new(Vec::new());

View File

@ -1,6 +1,6 @@
//! PCI/PCIe bus interfaces
#![no_std]
#![feature(let_chains)]
#![feature(let_chains, decl_macro)]
#![allow(clippy::missing_transmute_annotations)]
extern crate alloc;
@ -12,18 +12,23 @@ use acpi::mcfg::McfgEntry;
use alloc::{format, sync::Arc, vec::Vec};
use bitflags::bitflags;
use device::{PciBusDevice, PciDeviceInfo, PciDriver, PciMatch};
use device::{PciBusDevice, PciDeviceInfo};
use device_api::device::Device;
use interrupt::PciInterruptMap;
use libk::fs::sysfs::{self, object::KObject};
use libk_mm::address::PhysicalAddress;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit,
};
use space::legacy;
use yggdrasil_abi::{error::Error, primitive_enum};
pub mod capability;
pub mod device;
pub mod driver;
pub mod interrupt;
pub mod macros;
mod nodes;
mod space;
@ -88,20 +93,6 @@ primitive_enum! {
MsiX = 0x11,
}
}
// /// Unique ID assigned to PCI capability structures
// #[derive(Clone, Copy, PartialEq, Eq, Debug)]
// #[non_exhaustive]
// #[repr(u8)]
// pub enum PciCapabilityId {
// /// MSI (32-bit or 64-bit)
// Msi = 0x05,
// /// Vendor-specific capability
// VendorSpecific = 0x09,
// /// MSI-X
// MsiX = 0x11,
// /// Unknown capability missing from this list
// Unknown,
// }
/// Interface used for querying PCI capabilities
#[allow(unused)]
@ -609,88 +600,18 @@ fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
return Ok(());
}
log::debug!(
"{}: {:04x}:{:04x}",
device.info.address,
device.info.vendor_id,
device.info.device_id
);
if let Some(driver) = driver::lookup_driver(&device.info) {
log::info!("{} -> {}", device.info.address, driver.driver_name());
let instance = driver.probe(&device.info)?;
let drivers = PCI_DRIVERS.lock();
for driver in drivers.iter() {
if driver.check.check_device(&device.info) {
// TODO add the device to the bus
// log::debug!(" -> {:?}", driver.name);
let instance = (driver.probe)(&device.info)?;
unsafe { instance.clone().init() }?;
unsafe { instance.clone().init() }?;
device.device.replace(instance);
device.driver_name.replace(driver.name);
break;
}
device.device.replace(instance);
device.driver_name.replace(driver.driver_name());
}
Ok(())
}
impl PciMatch {
pub fn check_device(&self, info: &PciDeviceInfo) -> bool {
match self {
Self::Generic(f) => f(info),
&Self::Vendor(vendor_, device_) => {
info.vendor_id == vendor_ && info.device_id == device_
}
&Self::Class(class_, Some(subclass_), Some(prog_if_)) => {
class_ == info.class && subclass_ == info.subclass && prog_if_ == info.prog_if
}
&Self::Class(class_, Some(subclass_), _) => {
class_ == info.class && subclass_ == info.subclass
}
&Self::Class(class_, _, _) => class_ == info.class,
}
}
}
pub fn register_class_driver(
name: &'static str,
class: u8,
subclass: Option<u8>,
prog_if: Option<u8>,
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
) {
PCI_DRIVERS.lock().push(PciDriver {
name,
check: PciMatch::Class(class, subclass, prog_if),
probe,
});
}
pub fn register_vendor_driver(
name: &'static str,
vendor_id: u16,
device_id: u16,
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
) {
PCI_DRIVERS.lock().push(PciDriver {
name,
check: PciMatch::Vendor(vendor_id, device_id),
probe,
});
}
pub fn register_generic_driver(
name: &'static str,
check: fn(&PciDeviceInfo) -> bool,
probe: fn(&PciDeviceInfo) -> Result<Arc<dyn Device>, Error>,
) {
PCI_DRIVERS.lock().push(PciDriver {
name,
check: PciMatch::Generic(check),
probe,
});
}
static PCI_DRIVERS: IrqSafeSpinlock<Vec<PciDriver>> = IrqSafeSpinlock::new(Vec::new());
static PCI_MANAGER: IrqSafeSpinlock<PciBusManager> = IrqSafeSpinlock::new(PciBusManager::new());
static PCI_SYSFS_NODE: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();

View File

@ -0,0 +1,38 @@
use alloc::sync::Arc;
use device_api::device::Device;
pub macro pci_driver_match {
(class ($class:literal:$subclass:literal:$prog_if:literal)) => {
$crate::driver::PciMatch::Class($class, Some($subclass), Some($prog_if))
},
(class ($class:literal:$subclass:literal)) => {
$crate::driver::PciMatch::Class($class, Some($subclass), None)
},
(class $class:literal) => {
$crate::driver::PciMatch::Class($class, None, None)
},
(device ($vendor:literal:$device:literal)) => {
$crate::driver::PciMatch::Vendor($vendor, $device)
}
}
pub macro pci_driver(
matches: [$($kind:ident $match:tt),+],
driver: $driver:tt
) {
#[link_section = ".init_array"]
#[used]
static __REGISTER_FN: extern "C" fn() = __register_fn;
extern "C" fn __register_fn() {
struct Driver;
impl $crate::driver::PciDriver for Driver $driver
static DRIVER: Driver = Driver;
log::info!("register pci driver: {:?}", $crate::driver::PciDriver::driver_name(&Driver));
$(
let pmatch = $crate::macros::pci_driver_match!($kind $match);
$crate::driver::register_match(pmatch, &DRIVER);
)+
}
}

View File

@ -7,6 +7,7 @@ use rtl8139::Rtl8139;
use rtl8168::Rtl8168;
use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciBaseAddress, PciCommandRegister, PciConfigurationSpace,
};
@ -15,39 +16,57 @@ extern crate alloc;
pub mod rtl8139;
pub mod rtl8168;
pub fn probe_8168(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let base = info
.config_space
.bar(2)
.and_then(PciBaseAddress::as_memory)
.ok_or(Error::InvalidArgument)?;
pci_driver! {
matches: [device (0x10EC:0x8139)],
driver: {
fn driver_name(&self) -> &str {
"rtl8139"
}
// if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
// power.set_device_power_state(DevicePowerState::D0);
// }
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
info.init_interrupts(PreferredInterruptMode::Msi(false))?;
// Enable MMIO + interrupts + bus mastering
info.set_command(true, true, false, true);
// Enable MMIO + interrupts + bus mastering
let mut command = info.config_space.command();
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::ENABLE_MEMORY).bits();
command &= !(PciCommandRegister::ENABLE_IO | PciCommandRegister::DISABLE_INTERRUPTS).bits();
info.config_space.set_command(command);
let device = Rtl8168::new(base, info.clone())?;
Ok(Arc::new(device))
let base = info
.config_space
.bar(1)
.and_then(PciBaseAddress::as_memory)
.ok_or(Error::InvalidArgument)?;
let device = Rtl8139::new(base, info.clone())?;
Ok(Arc::new(device))
}
}
}
pub fn probe_8139(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
info.init_interrupts(PreferredInterruptMode::Msi(false))?;
pci_driver! {
matches: [device (0x10EC:0x8168)],
driver: {
fn driver_name(&self) -> &str {
"rtl816x"
}
// Enable MMIO + interrupts + bus mastering
let mut command = info.config_space.command();
command |= (PciCommandRegister::BUS_MASTER | PciCommandRegister::ENABLE_MEMORY).bits();
command &= !(PciCommandRegister::ENABLE_IO | PciCommandRegister::DISABLE_INTERRUPTS).bits();
info.config_space.set_command(command);
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let base = info
.config_space
.bar(2)
.and_then(PciBaseAddress::as_memory)
.ok_or(Error::InvalidArgument)?;
let base = info
.config_space
.bar(1)
.and_then(PciBaseAddress::as_memory)
.ok_or(Error::InvalidArgument)?;
// if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
// power.set_device_power_state(DevicePowerState::D0);
// }
let device = Rtl8139::new(base, info.clone())?;
Ok(Arc::new(device))
// Enable MMIO + interrupts + bus mastering
info.set_command(true, true, false, true);
let device = Rtl8168::new(base, info.clone())?;
Ok(Arc::new(device))
}
}
}

View File

@ -8,11 +8,10 @@ use alloc::sync::Arc;
use controller::Xhci;
use device_api::{device::Device, interrupt::InterruptAffinity};
use regs::Regs;
// use regs::Mapper;
// use xhci_lib::extended_capabilities;
use ygg_driver_pci::{
capability::{DevicePowerState, PowerManagementCapability},
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciCommandRegister, PciConfigurationSpace,
};
use yggdrasil_abi::error::Error;
@ -21,37 +20,48 @@ mod controller;
mod regs;
mod ring;
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
// TODO Chip Hardware Reset
let bar0 = info
.config_space
.bar(0)
.expect("xHCI doesn't have BAR0 configured")
.as_memory()
.expect("xHCI's BAR0 is not memory-type");
if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
log::info!("xHC has power management capability");
let power_state = power.get_device_power_state();
if power_state != DevicePowerState::D0 {
power.set_device_power_state(DevicePowerState::D0);
// Only x86-64 supports xHCI currently, because only it has MSI-X implemented
#[cfg(target_arch = "x86_64")]
pci_driver! {
matches: [class (0x0C:0x03:0x30)],
driver: {
fn driver_name(&self) -> &str {
"xhci"
}
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
// TODO Chip Hardware Reset
let bar0 = info
.config_space
.bar(0)
.expect("xHCI doesn't have BAR0 configured")
.as_memory()
.expect("xHCI's BAR0 is not memory-type");
if let Some(power) = info.config_space.capability::<PowerManagementCapability>() {
log::info!("xHC has power management capability");
let power_state = power.get_device_power_state();
if power_state != DevicePowerState::D0 {
power.set_device_power_state(DevicePowerState::D0);
}
// Enable PME# signal generation
power.set_pme_en(true);
}
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
let regs = Regs::map(bar0)?;
let xhci = Arc::new(Xhci::new(info.clone(), regs)?);
info.map_interrupt(InterruptAffinity::Any, xhci.clone())?;
Ok(xhci)
}
// Enable PME# signal generation
power.set_pme_en(true);
}
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
info.config_space.set_command(cmd.bits());
info.init_interrupts(PreferredInterruptMode::Msi(true))?;
let regs = Regs::map(bar0)?;
let xhci = Arc::new(Xhci::new(info.clone(), regs)?);
info.map_interrupt(InterruptAffinity::Any, xhci.clone())?;
Ok(xhci)
}

View File

@ -23,7 +23,7 @@ use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit,
};
use ygg_driver_pci::device::PciDeviceInfo;
use ygg_driver_pci::{device::PciDeviceInfo, macros::pci_driver};
use ygg_driver_virtio_core::{
queue::VirtQueue,
transport::{pci::PciTransport, Transport},
@ -389,17 +389,26 @@ impl<T: Transport + 'static> DisplayDevice for VirtioGpu<T> {
}
}
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let space = &info.config_space;
pci_driver! {
matches: [device (0x1AF4:0x1050)],
driver: {
fn driver_name(&self) -> &str {
"virtio-gpu"
}
let transport = PciTransport::from_config_space(space)
.inspect_err(|error| {
log::error!("Couldn't set up PCI virtio transport: {error:?}");
})
.map_err(|_| Error::InvalidArgument)?;
let device = VirtioGpu::new(transport, Some(info.clone()))?;
let device = Arc::new(device);
// let device = Box::leak(Box::new(device));
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let space = &info.config_space;
Ok(device)
let transport = PciTransport::from_config_space(space)
.inspect_err(|error| {
log::error!("Couldn't set up PCI virtio transport: {error:?}");
})
.map_err(|_| Error::InvalidArgument)?;
let device = VirtioGpu::new(transport, Some(info.clone()))?;
let device = Arc::new(device);
// let device = Box::leak(Box::new(device));
Ok(device)
}
}
}

View File

@ -20,7 +20,10 @@ use ygg_driver_net_core::{
interface::{NetworkDevice, NetworkInterfaceType},
Packet,
};
use ygg_driver_pci::device::{PciDeviceInfo, PreferredInterruptMode};
use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
};
use ygg_driver_virtio_core::{
queue::VirtQueue,
transport::{pci::PciTransport, Transport},
@ -296,13 +299,22 @@ fn cvt_error(error: ygg_driver_virtio_core::error::Error) -> Error {
}
}
pub fn probe(info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let space = &info.config_space;
pci_driver! {
matches: [device (0x1AF4:0x1000)],
driver: {
fn driver_name(&self) -> &str {
"virtio-net"
}
let transport = PciTransport::from_config_space(space).unwrap();
let device = VirtioNet::new(transport, Some(info.clone()));
fn probe(&self, info: &PciDeviceInfo) -> Result<Arc<dyn Device>, Error> {
let space = &info.config_space;
let device = Arc::new(device);
let transport = PciTransport::from_config_space(space).unwrap();
let device = VirtioNet::new(transport, Some(info.clone()));
Ok(device)
let device = Arc::new(device);
Ok(device)
}
}
}

View File

@ -30,7 +30,7 @@ use libk_mm::{
};
use peripherals::textfb::TextFramebuffer;
use crate::arch::x86;
use crate::{arch::x86, util::call_init_array};
use super::Platform;
@ -162,8 +162,6 @@ impl I686 {
self.init_cpu().expect("Could not initialize CPU");
x86::register_pci_drivers();
let early = x86::init_platform_early(cmdline)?;
if !config::get().x86.disable_boot_fb {
@ -173,6 +171,9 @@ impl I686 {
}
x86::add_legacy_pci();
call_init_array();
x86::init_platform_devices(early);
Ok(())

View File

@ -50,59 +50,6 @@ pub enum SelectedClockSource {
Fallback(Arc<I8253>),
}
// TODO move this to some sort of .init_array-style implicit thing
pub fn register_pci_drivers() {
// XXX: Only works with MSI-X, so no i686
// #[cfg(any(target_arch = "x86_64", rust_analyzer))]
// ygg_driver_pci::register_class_driver(
// "NVMe Host Controller",
// 0x01,
// Some(0x08),
// Some(0x02),
// ygg_driver_nvme::probe,
// );
// XXX: i686 hangs in interrupt handler
// #[cfg(any(target_arch = "x86_64", rust_analyzer))]
// ygg_driver_pci::register_class_driver(
// "AHCI Controller",
// 0x01,
// Some(0x06),
// Some(0x01),
// ygg_driver_ahci::probe,
// );
ygg_driver_pci::register_class_driver(
"USB xHCI",
0x0C,
Some(0x03),
Some(0x30),
ygg_driver_usb_xhci::probe,
);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI GPU Device",
0x1AF4,
0x1050,
ygg_driver_virtio_gpu::probe,
);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI Network Device",
0x1AF4,
0x1000,
ygg_driver_virtio_net::probe,
);
ygg_driver_pci::register_vendor_driver(
"Realtek RTL8139 10/100Mbps Ethernet",
0x10EC,
0x8139,
ygg_driver_net_rtl81xx::probe_8139,
);
ygg_driver_pci::register_vendor_driver(
"Realtek RTL8168/8111 Gigabit Ethernet",
0x10EC,
0x8168,
ygg_driver_net_rtl81xx::probe_8168,
);
}
// Initialize the bare minimum required to:
// * Allocate/manage interrupts
// * Print debug output

View File

@ -50,6 +50,7 @@ mod syscall;
use crate::{
arch::x86::{self, peripherals::hpet::Hpet},
device::display::linear_fb::LinearFramebuffer,
util::call_init_array,
};
use self::boot::BootData;
@ -253,8 +254,6 @@ impl X86_64 {
self.init_local_cpu(cpu_id, available_features, enabled_features);
if cpu_id == 0 {
x86::register_pci_drivers();
self.setup_from_boot_data()?;
// TODO yboot doesn't yet pass any command line options
@ -277,6 +276,8 @@ impl X86_64 {
log::info!("HPET disabled by config");
}
call_init_array();
x86::init_platform_devices(early);
}

View File

@ -39,6 +39,7 @@
use abi::{error::Error, io::FileMode};
use alloc::string::String;
use arch::Platform;
use cfg_if::cfg_if;
use git_version::git_version;
use kernel_arch::{Architecture, ArchitectureImpl};
use libk::{
@ -61,6 +62,19 @@ extern crate alloc;
#[cfg(not(rust_analyzer))]
extern crate compiler_builtins;
cfg_if! {
if #[cfg(any(target_arch = "x86_64", rust_analyzer))] {
extern crate ygg_driver_net_rtl81xx;
extern crate ygg_driver_usb_xhci;
extern crate ygg_driver_nvme;
}
}
extern crate ygg_driver_ahci;
extern crate ygg_driver_virtio_gpu;
extern crate ygg_driver_virtio_net;
#[macro_use]
pub mod arch;