diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8a5f328c2..d4dbc383fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -137,7 +137,7 @@ jobs: run: rustup show - uses: Swatinem/rust-cache@v2 - name: Build dev profile - run: cargo build -Zbuild-std=std,panic_abort --package rusty_demo --target x86_64-unknown-hermit + run: cargo build -Zbuild-std=std,panic_abort --package rusty_demo --target x86_64-unknown-hermit --features pci-ids - name: Download loader uses: dsaltares/fetch-gh-release-asset@1.1.1 with: @@ -157,7 +157,7 @@ jobs: -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on -numa node,memdev=mem \ -initrd target/x86_64-unknown-hermit/debug/rusty_demo - name: Build release profile - run: cargo build -Zbuild-std=std,panic_abort --package rusty_demo --target x86_64-unknown-hermit --release + run: cargo build -Zbuild-std=std,panic_abort --package rusty_demo --target x86_64-unknown-hermit --release --features pci-ids - name: Test release profile run: | virtiofsd --socket-path=./vhostqemu --shared-dir ./img --announce-submounts --sandbox none --seccomp none --inode-file-handles=never & @@ -169,6 +169,34 @@ jobs: -device vhost-user-fs-pci,queue-size=1024,chardev=char0,tag=root \ -object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on -numa node,memdev=mem \ -initrd target/x86_64-unknown-hermit/release/rusty_demo + - name: Build httpd with DHCP support (debug profile) + run: + cargo build -Zbuild-std=std,panic_abort --target x86_64-unknown-hermit --package httpd --features ci,dhcpv4 + - name: Test httpd with DHCP support (debug profile) + run: | + qemu-system-x86_64 -smp 1 -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand \ + -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none -m 128M -serial stdio \ + -kernel rusty-loader-x86_64 \ + -initrd target/x86_64-unknown-hermit/debug/httpd \ + -netdev user,id=u1,hostfwd=tcp::9975-:9975,net=192.168.76.0/24,dhcpstart=192.168.76.9 \ + -device rtl8139,netdev=u1 & + sleep 5 + curl http://127.0.0.1:9975/help + sleep 1 + - name: Build httpd with DHCP support (release profile) + run: + cargo build -Zbuild-std=std,panic_abort --target x86_64-unknown-hermit --package httpd --release --features ci,dhcpv4 + - name: Test httpd with DHCP support (release profile) + run: | + qemu-system-x86_64 -smp 1 -cpu qemu64,apic,fsgsbase,rdtscp,xsave,xsaveopt,fxsr,rdrand \ + -device isa-debug-exit,iobase=0xf4,iosize=0x04 -display none -m 128M -serial stdio \ + -kernel rusty-loader-x86_64 \ + -initrd target/x86_64-unknown-hermit/release/httpd \ + -netdev user,id=u1,hostfwd=tcp::9975-:9975,net=192.168.76.0/24,dhcpstart=192.168.76.9 \ + -device rtl8139,netdev=u1 & + sleep 5 + curl http://127.0.0.1:9975/help + sleep 1 - name: Build minimal profile run: cargo build -Zbuild-std=std,panic_abort --target x86_64-unknown-hermit --no-default-features --release --package hello_world - name: Test minimal profile @@ -216,7 +244,7 @@ jobs: sudo apt-get install qemu-system-aarch64 - uses: Swatinem/rust-cache@v2 - name: Build dev profile - run: cargo build -Zbuild-std=std,panic_abort --target aarch64-unknown-hermit --package rusty_demo + run: cargo build -Zbuild-std=std,panic_abort --target aarch64-unknown-hermit --package rusty_demo --features pci-ids - name: Test dev kernel run: | qemu-system-aarch64 -semihosting \ @@ -224,7 +252,7 @@ jobs: -m 512M -cpu max -smp 1 -display none -serial stdio -kernel rusty-loader-aarch64 \ -device guest-loader,addr=0x48000000,initrd=target/aarch64-unknown-hermit/debug/rusty_demo - name: Build release profile - run: cargo build -Zbuild-std=std,panic_abort --target aarch64-unknown-hermit --package rusty_demo --release + run: cargo build -Zbuild-std=std,panic_abort --target aarch64-unknown-hermit --package rusty_demo --release --features pci-ids - name: Test release kernel run: | qemu-system-aarch64 -semihosting \ diff --git a/Cargo.lock b/Cargo.lock index 6a36eb8e78..d220f9c98e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "defmt-macros" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82610855c67a4dc36299cc6bfcf140f329e4f013582531c7ba7d32512ddabc47" +checksum = "b4abc4821bd84d3d8f49945ddb24d029be9385ed9b77c99bf2f6296847a6a9f0" dependencies = [ "defmt-parser", "proc-macro-error", @@ -150,9 +150,9 @@ dependencies = [ [[package]] name = "defmt-parser" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15e994575e38332cf4a2dc9dc745ff6a65695d37a41e00efadd57fcd42c1ba4" +checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" dependencies = [ "thiserror", ] @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libhermit-rs" @@ -374,6 +374,7 @@ dependencies = [ "num-derive", "num-traits", "pci-ids", + "pci_types", "pflock", "qemu-exit", "rand_chacha", @@ -395,9 +396,9 @@ checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" [[package]] name = "linux-raw-sys" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" [[package]] name = "llvm-tools" @@ -560,6 +561,14 @@ dependencies = [ "quote", ] +[[package]] +name = "pci_types" +version = "0.4.0" +source = "git+https://github.com/hermitcore/pci_types.git?branch=hermit#87f0e23e0e4a6afc11674e5a2f8847188244ae69" +dependencies = [ + "bit_field", +] + [[package]] name = "pflock" version = "0.2.0" @@ -666,9 +675,9 @@ checksum = "9ff023245bfcc73fb890e1f8d5383825b3131cc920020a5c487d6f113dfc428a" [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -727,9 +736,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.15" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags 1.3.2", "errno", diff --git a/Cargo.toml b/Cargo.toml index ee0cb4f330..833d82c827 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,7 @@ num-traits = { version = "0.2", default-features = false } num-derive = "0.3" zerocopy = "0.6" time = { version = "0.3", default-features = false } +pci_types = { git = "https://github.com/hermitcore/pci_types.git", branch = "hermit" } [dependencies.smoltcp] version = "0.9" diff --git a/src/arch/aarch64/kernel/core_local.rs b/src/arch/aarch64/kernel/core_local.rs index 65dae37335..14f8afb0a6 100644 --- a/src/arch/aarch64/kernel/core_local.rs +++ b/src/arch/aarch64/kernel/core_local.rs @@ -1,5 +1,9 @@ +use alloc::boxed::Box; use core::ptr; +use core::sync::atomic::Ordering; +use super::interrupts::{IrqStatistics, IRQ_COUNTERS}; +use super::CPU_ONLINE; use crate::scheduler::{CoreId, PerCoreScheduler}; #[no_mangle] @@ -19,6 +23,13 @@ impl CoreLocal { scheduler: CoreLocalVariable::new(0 as *mut PerCoreScheduler), } } + + pub fn install() { + let core_id = CPU_ONLINE.load(Ordering::Relaxed); + + let irq_statistics = &*Box::leak(Box::new(IrqStatistics::new())); + IRQ_COUNTERS.lock().insert(core_id, irq_statistics); + } } #[repr(C)] @@ -72,6 +83,13 @@ pub fn set_core_scheduler(scheduler: *mut PerCoreScheduler) { } } -pub fn init() { - // TODO: Implement! +pub fn increment_irq_counter(irq_no: u8) { + unsafe { + let id = CORE_LOCAL.core_id.get(); + if let Some(counter) = IRQ_COUNTERS.lock().get(&id) { + counter.inc(irq_no); + } else { + warn!("Unknown core {}, is core {} already registered?", id, id); + } + } } diff --git a/src/arch/aarch64/kernel/interrupts.rs b/src/arch/aarch64/kernel/interrupts.rs index 2829fa536f..edfa9a7227 100644 --- a/src/arch/aarch64/kernel/interrupts.rs +++ b/src/arch/aarch64/kernel/interrupts.rs @@ -1,19 +1,21 @@ +use alloc::collections::BTreeMap; use alloc::vec::Vec; use core::arch::asm; -use core::ptr; +use core::sync::atomic::{AtomicU64, Ordering}; use aarch64::regs::*; -use arm_gic::gicv3::{GicV3, IntId, SgiTarget}; +use ahash::RandomState; +use arm_gic::gicv3::{GicV3, IntId}; +use hashbrown::HashMap; use hermit_dtb::Dtb; -use hermit_sync::{without_interrupts, InterruptTicketMutex, OnceCell}; +use hermit_sync::{InterruptSpinMutex, InterruptTicketMutex, OnceCell}; use tock_registers::interfaces::Readable; use crate::arch::aarch64::kernel::boot_info; +use crate::arch::aarch64::kernel::core_local::increment_irq_counter; use crate::arch::aarch64::kernel::scheduler::State; -use crate::arch::aarch64::mm::paging::{ - self, virt_to_phys, BasePageSize, PageSize, PageTableEntryFlags, -}; -use crate::arch::aarch64::mm::{virtualmem, PhysAddr, VirtAddr}; +use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags}; +use crate::arch::aarch64::mm::{virtualmem, PhysAddr}; use crate::errno::EFAULT; use crate::scheduler::CoreId; use crate::{core_scheduler, sys_exit}; @@ -83,10 +85,10 @@ pub fn disable() { } } -pub fn irq_install_handler(irq_number: u32, handler: fn(state: &State)) { +pub fn irq_install_handler(irq_number: u8, handler: fn(state: &State)) { debug!("Install handler for interrupt {}", irq_number); unsafe { - INTERRUPT_HANDLERS[irq_number as usize] = Some(handler); + INTERRUPT_HANDLERS[irq_number as usize + 16] = Some(handler); } } @@ -96,6 +98,7 @@ pub extern "C" fn do_fiq(state: &State) { let vector: usize = u32::from(irqid).try_into().unwrap(); debug!("Receive fiq {}", vector); + increment_irq_counter(vector.try_into().unwrap()); if vector < MAX_HANDLERS { unsafe { @@ -122,6 +125,7 @@ pub extern "C" fn do_irq(state: &State) { let vector: usize = u32::from(irqid).try_into().unwrap(); debug!("Receive interrupt {}", vector); + increment_irq_counter(vector.try_into().unwrap()); if vector < MAX_HANDLERS { unsafe { @@ -276,8 +280,9 @@ pub fn init() { TIMER_INTERRUPT = irq; } - info!("Timer interrupt: {}", irq); - irq_install_handler(irq + 16, timer_handler); + debug!("Timer interrupt: {}", irq); + irq_install_handler(irq.try_into().unwrap(), timer_handler); + add_irq_name(irq.try_into().unwrap(), "Timer"); // enable timer interrupt let timer_irqid = IntId::ppi(irq); @@ -291,3 +296,55 @@ pub fn init() { GIC.set(gic).unwrap(); } } + +static IRQ_NAMES: InterruptTicketMutex> = + InterruptTicketMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0))); + +pub fn add_irq_name(irq_number: u8, name: &'static str) { + debug!("Register name \"{}\" for interrupt {}", name, irq_number); + IRQ_NAMES.lock().insert(16 + irq_number, name); +} + +fn get_irq_name(irq_number: u8) -> Option<&'static str> { + IRQ_NAMES.lock().get(&irq_number).copied() +} + +pub static IRQ_COUNTERS: InterruptSpinMutex> = + InterruptSpinMutex::new(BTreeMap::new()); + +pub struct IrqStatistics { + pub counters: [AtomicU64; 256], +} + +impl IrqStatistics { + pub const fn new() -> Self { + #[allow(clippy::declare_interior_mutable_const)] + const NEW_COUNTER: AtomicU64 = AtomicU64::new(0); + IrqStatistics { + counters: [NEW_COUNTER; 256], + } + } + + pub fn inc(&self, pos: u8) { + self.counters[usize::from(pos)].fetch_add(1, Ordering::Relaxed); + } +} + +pub fn print_statistics() { + info!("Number of interrupts"); + for (core_id, irg_statistics) in IRQ_COUNTERS.lock().iter() { + for (i, counter) in irg_statistics.counters.iter().enumerate() { + let counter = counter.load(Ordering::Relaxed); + if counter > 0 { + match get_irq_name(i.try_into().unwrap()) { + Some(name) => { + info!("[{core_id}][{name}]: {counter}"); + } + _ => { + info!("[{core_id}][{i}]: {counter}"); + } + } + } + } + } +} diff --git a/src/arch/aarch64/kernel/mmio.rs b/src/arch/aarch64/kernel/mmio.rs new file mode 100644 index 0000000000..90c88fbe50 --- /dev/null +++ b/src/arch/aarch64/kernel/mmio.rs @@ -0,0 +1,7 @@ +use hermit_sync::InterruptTicketMutex; + +use crate::drivers::net::NetworkInterface; + +pub fn get_network_driver() -> Option<&'static InterruptTicketMutex> { + None +} diff --git a/src/arch/aarch64/kernel/mod.rs b/src/arch/aarch64/kernel/mod.rs index 48134b0b24..6b245f9e1d 100644 --- a/src/arch/aarch64/kernel/mod.rs +++ b/src/arch/aarch64/kernel/mod.rs @@ -1,5 +1,9 @@ pub mod core_local; pub mod interrupts; +#[cfg(not(feature = "pci"))] +pub mod mmio; +#[cfg(feature = "pci")] +pub mod pci; pub mod processor; pub mod scheduler; pub mod serial; @@ -9,6 +13,7 @@ pub mod systemtime; use core::arch::{asm, global_asm}; use core::ptr; +use core::sync::atomic::{AtomicU32, Ordering}; use hermit_entry::boot_info::{BootInfo, PlatformInfo, RawBootInfo}; use hermit_sync::TicketMutex; @@ -23,7 +28,11 @@ use crate::env; const SERIAL_PORT_BAUDRATE: u32 = 115200; static mut COM1: SerialPort = SerialPort::new(0x800); -static CPU_ONLINE: TicketMutex = TicketMutex::new(0); + +/// `CPU_ONLINE` is the count of CPUs that finished initialization. +/// +/// It also synchronizes initialization of CPU cores. +pub static CPU_ONLINE: AtomicU32 = AtomicU32::new(0); global_asm!(include_str!("start.s")); @@ -44,6 +53,10 @@ pub fn get_boot_info_address() -> VirtAddr { VirtAddr(raw_boot_info() as *const _ as u64) } +pub fn is_uhyve_with_pci() -> bool { + false +} + pub fn get_ram_address() -> PhysAddr { PhysAddr(boot_info().hardware_info.phys_addr_range.start) } @@ -101,7 +114,7 @@ pub fn get_tls_align() -> usize { #[cfg(feature = "smp")] pub fn get_possible_cpus() -> u32 { - 1 + CPU_ONLINE.load(Ordering::Acquire) } #[cfg(feature = "smp")] @@ -142,7 +155,7 @@ pub fn get_cmdline() -> VirtAddr { /// Earliest initialization function called by the Boot Processor. pub fn message_output_init() { - core_local::init(); + CoreLocal::install(); unsafe { COM1.port_address = boot_info() @@ -186,6 +199,8 @@ pub fn boot_processor_init() { processor::detect_frequency(); processor::print_information(); systemtime::init(); + #[cfg(feature = "pci")] + pci::init(); finish_processor_init(); } @@ -198,21 +213,16 @@ pub fn boot_application_processors() { /// Application Processor initialization pub fn application_processor_init() { - core_local::init(); + CoreLocal::install(); finish_processor_init(); } fn finish_processor_init() { debug!("Initialized Processor"); - // This triggers apic::boot_application_processors (bare-metal/QEMU) or uhyve - // to initialize the next processor. - *CPU_ONLINE.lock() += 1; + CPU_ONLINE.fetch_add(1, Ordering::Release); } -pub fn network_adapter_init() -> i32 { - // AArch64 supports no network adapters on bare-metal/QEMU, so return a failure code. - -1 +pub fn print_statistics() { + interrupts::print_statistics(); } - -pub fn print_statistics() {} diff --git a/src/arch/aarch64/kernel/pci.rs b/src/arch/aarch64/kernel/pci.rs new file mode 100644 index 0000000000..6042af8377 --- /dev/null +++ b/src/arch/aarch64/kernel/pci.rs @@ -0,0 +1,126 @@ +use alloc::vec::Vec; +use core::{str, u32, u64, u8}; + +use hermit_dtb::Dtb; +use pci_types::{ConfigRegionAccess, PciAddress, PciHeader}; + +use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags}; +use crate::arch::aarch64::mm::{virtualmem, PhysAddr, VirtAddr}; +use crate::drivers::pci::{PciDevice, PCI_DEVICES}; +use crate::kernel::boot_info; + +const PCI_MAX_DEVICE_NUMBER: u8 = 32; +const PCI_MAX_FUNCTION_NUMBER: u8 = 8; + +#[derive(Debug, Copy, Clone)] +pub(crate) struct PciConfigRegion(VirtAddr); + +impl PciConfigRegion { + pub const fn new(addr: VirtAddr) -> Self { + assert!(addr.as_u64() & 0xFFFFFFF == 0, "Unaligend PCI Config Space"); + Self(addr) + } +} + +impl ConfigRegionAccess for PciConfigRegion { + #[inline] + fn function_exists(&self, _address: PciAddress) -> bool { + // we trust the device tree + true + } + + #[inline] + unsafe fn read(&self, pci_addr: PciAddress, offset: u16) -> u32 { + assert!(offset & 0xF000 == 0, "Inavlid offset"); + let addr = u64::from(pci_addr.bus()) << 20 + | u64::from(pci_addr.device()) << 15 + | u64::from(pci_addr.function()) << 12 + | (u64::from(offset) & 0xFFF) + | self.0.as_u64(); + unsafe { + crate::drivers::pci::from_pci_endian(core::ptr::read_volatile(addr as *const u32)) + } + } + + #[inline] + unsafe fn write(&self, pci_addr: PciAddress, offset: u16, value: u32) { + assert!(offset & 0xF000 == 0, "Inavlid offset"); + let addr = u64::from(pci_addr.bus()) << 20 + | u64::from(pci_addr.device()) << 15 + | u64::from(pci_addr.function()) << 12 + | (u64::from(offset) & 0xFFF) + | self.0.as_u64(); + unsafe { + core::ptr::write_volatile(addr as *mut u32, value.to_le()); + } + } +} + +pub fn init() { + let dtb = unsafe { + Dtb::from_raw(boot_info().hardware_info.device_tree.unwrap().get() as *const u8) + .expect(".dtb file has invalid header") + }; + + for node in dtb.enum_subnodes("/") { + let parts: Vec<_> = node.split('@').collect(); + + if let Some(compatible) = dtb.get_property(parts.first().unwrap(), "compatible") { + if str::from_utf8(compatible) + .unwrap() + .find("pci-host-ecam-generic") + .is_some() + { + let reg = dtb.get_property(parts.first().unwrap(), "reg").unwrap(); + let (slice, residual_slice) = reg.split_at(core::mem::size_of::()); + let addr = PhysAddr(u64::from_be_bytes(slice.try_into().unwrap())); + let (slice, _residual_slice) = residual_slice.split_at(core::mem::size_of::()); + let size = u64::from_be_bytes(slice.try_into().unwrap()); + + let pci_address = + virtualmem::allocate_aligned(size.try_into().unwrap(), 0x10000000).unwrap(); + info!("Mapping PCI Enhanced Configuration Space interface to virtual address {:#X} (size {:#X})", pci_address, size); + + let mut flags = PageTableEntryFlags::empty(); + flags.device().writable().execute_disable(); + paging::map::( + pci_address, + addr, + (size / BasePageSize::SIZE).try_into().unwrap(), + flags, + ); + + let max_bus_number = size + / (PCI_MAX_DEVICE_NUMBER as u64 + * PCI_MAX_FUNCTION_NUMBER as u64 + * BasePageSize::SIZE); + info!("Scanning PCI Busses 0 to {}", max_bus_number - 1); + + let pci_config = PciConfigRegion::new(pci_address); + for bus in 0..max_bus_number { + for device in 0..PCI_MAX_DEVICE_NUMBER { + let pci_address = PciAddress::new(0, bus.try_into().unwrap(), device, 0); + let header = PciHeader::new(pci_address); + + let (device_id, vendor_id) = header.id(&pci_config); + if device_id != u16::MAX && vendor_id != u16::MAX { + unsafe { + PCI_DEVICES.push(PciDevice::new(pci_address, pci_config)); + } + } + } + } + + return; + } else if str::from_utf8(compatible) + .unwrap() + .find("pci-host-cam-generic") + .is_some() + { + warn!("Currently, pci-host-cam-generic isn't supported!"); + } + } + } + + warn!("Unable to find PCI bus"); +} diff --git a/src/arch/aarch64/kernel/scheduler.rs b/src/arch/aarch64/kernel/scheduler.rs index f0c8f5f6fc..9323895223 100644 --- a/src/arch/aarch64/kernel/scheduler.rs +++ b/src/arch/aarch64/kernel/scheduler.rs @@ -2,9 +2,7 @@ use alloc::alloc::{alloc_zeroed, Layout}; use alloc::boxed::Box; -use alloc::rc::Rc; use core::arch::asm; -use core::cell::RefCell; use core::{mem, ptr, slice}; use align_address::Align; diff --git a/src/arch/aarch64/kernel/switch.rs b/src/arch/aarch64/kernel/switch.rs index 4d717620a5..8bdf279e6d 100644 --- a/src/arch/aarch64/kernel/switch.rs +++ b/src/arch/aarch64/kernel/switch.rs @@ -1,63 +1,65 @@ use core::arch::asm; -#[inline] +#[inline(always)] pub unsafe extern "C" fn switch_to_fpu_owner(old_stack: *mut usize, new_stack: usize) { switch_to_task(old_stack, new_stack); } #[naked] pub unsafe extern "C" fn switch_to_task(_old_stack: *mut usize, _new_stack: usize) { - asm!( - // save general purpose registers - "stp x29, x30, [sp, #-16]!", - "stp x27, x28, [sp, #-16]!", - "stp x25, x26, [sp, #-16]!", - "stp x23, x24, [sp, #-16]!", - "stp x21, x22, [sp, #-16]!", - "stp x19, x20, [sp, #-16]!", - "stp x17, x18, [sp, #-16]!", - "stp x15, x16, [sp, #-16]!", - "stp x13, x14, [sp, #-16]!", - "stp x11, x12, [sp, #-16]!", - "stp x9, x10, [sp, #-16]!", - "stp x7, x8, [sp, #-16]!", - "stp x5, x6, [sp, #-16]!", - "stp x3, x4, [sp, #-16]!", - "stp x1, x2, [sp, #-16]!", - // save thread id register and process state - "mrs x22, tpidr_el0", - "stp x22, x0, [sp, #-16]!", - "mrs x22, elr_el1", - "mrs x23, spsr_el1", - "stp x22, x23, [sp, #-16]!", - // Store the old `sp` behind `old_stack` - "mov x24, sp", - "str x24, [x0]", - // Set `sp` to `new_stack` - "mov sp, x1", - // restore thread id register and process state - "ldp x22, x23, [sp], #16", - "msr elr_el1, x22", - "msr spsr_el1, x23", - "ldp x22, x0, [sp], #16", - "msr tpidr_el0, x22", - // restore general purpose registers - "ldp x1, x2, [sp], #16", - "ldp x3, x4, [sp], #16", - "ldp x5, x6, [sp], #16", - "ldp x7, x8, [sp], #16", - "ldp x9, x10, [sp], #16", - "ldp x11, x12, [sp], #16", - "ldp x13, x14, [sp], #16", - "ldp x15, x16, [sp], #16", - "ldp x17, x18, [sp], #16", - "ldp x19, x20, [sp], #16", - "ldp x21, x22, [sp], #16", - "ldp x23, x24, [sp], #16", - "ldp x25, x26, [sp], #16", - "ldp x27, x28, [sp], #16", - "ldp x29, x30, [sp], #16", - "ret", - options(noreturn), - ); + unsafe { + asm!( + // save general purpose registers + "stp x29, x30, [sp, #-16]!", + "stp x27, x28, [sp, #-16]!", + "stp x25, x26, [sp, #-16]!", + "stp x23, x24, [sp, #-16]!", + "stp x21, x22, [sp, #-16]!", + "stp x19, x20, [sp, #-16]!", + "stp x17, x18, [sp, #-16]!", + "stp x15, x16, [sp, #-16]!", + "stp x13, x14, [sp, #-16]!", + "stp x11, x12, [sp, #-16]!", + "stp x9, x10, [sp, #-16]!", + "stp x7, x8, [sp, #-16]!", + "stp x5, x6, [sp, #-16]!", + "stp x3, x4, [sp, #-16]!", + "stp x1, x2, [sp, #-16]!", + // save thread id register and process state + "mrs x22, tpidr_el0", + "stp x22, x0, [sp, #-16]!", + "mrs x22, elr_el1", + "mrs x23, spsr_el1", + "stp x22, x23, [sp, #-16]!", + // Store the old `sp` behind `old_stack` + "mov x24, sp", + "str x24, [x0]", + // Set `sp` to `new_stack` + "mov sp, x1", + // restore thread id register and process state + "ldp x22, x23, [sp], #16", + "msr elr_el1, x22", + "msr spsr_el1, x23", + "ldp x22, x0, [sp], #16", + "msr tpidr_el0, x22", + // restore general purpose registers + "ldp x1, x2, [sp], #16", + "ldp x3, x4, [sp], #16", + "ldp x5, x6, [sp], #16", + "ldp x7, x8, [sp], #16", + "ldp x9, x10, [sp], #16", + "ldp x11, x12, [sp], #16", + "ldp x13, x14, [sp], #16", + "ldp x15, x16, [sp], #16", + "ldp x17, x18, [sp], #16", + "ldp x19, x20, [sp], #16", + "ldp x21, x22, [sp], #16", + "ldp x23, x24, [sp], #16", + "ldp x25, x26, [sp], #16", + "ldp x27, x28, [sp], #16", + "ldp x29, x30, [sp], #16", + "ret", + options(noreturn), + ); + } } diff --git a/src/arch/aarch64/kernel/systemtime.rs b/src/arch/aarch64/kernel/systemtime.rs index 41b6d0bdc7..0189b0e649 100644 --- a/src/arch/aarch64/kernel/systemtime.rs +++ b/src/arch/aarch64/kernel/systemtime.rs @@ -60,7 +60,7 @@ pub fn init() { let reg = dtb.get_property(parts.first().unwrap(), "reg").unwrap(); let (slice, residual_slice) = reg.split_at(core::mem::size_of::()); let addr = PhysAddr(u64::from_be_bytes(slice.try_into().unwrap())); - let (slice, residual_slice) = residual_slice.split_at(core::mem::size_of::()); + let (slice, _residual_slice) = residual_slice.split_at(core::mem::size_of::()); let size = u64::from_be_bytes(slice.try_into().unwrap()); debug!("Found RTC at {:#X} (size {:#X})", addr, size); diff --git a/src/arch/aarch64/mm/paging.rs b/src/arch/aarch64/mm/paging.rs index fb3b813647..7890744235 100644 --- a/src/arch/aarch64/mm/paging.rs +++ b/src/arch/aarch64/mm/paging.rs @@ -4,7 +4,6 @@ use core::{fmt, mem, ptr, usize}; use align_address::Align; -use crate::arch::aarch64::kernel::core_local::*; use crate::arch::aarch64::kernel::{ get_base_address, get_boot_info_address, get_image_size, get_ram_address, processor, }; @@ -639,11 +638,13 @@ pub unsafe fn init() { info!("RAM starts at physical address 0x{:x}", ram_start); // determine physical address size - asm!( - "mrs {}, id_aa64mmfr0_el1", - out(reg) aa64mmfr0, - options(nostack), - ); + unsafe { + asm!( + "mrs {}, id_aa64mmfr0_el1", + out(reg) aa64mmfr0, + options(nostack), + ); + } let pa_range: u64 = match aa64mmfr0 & 0b1111 { 0b0000 => 32, diff --git a/src/arch/mod.rs b/src/arch/mod.rs index cf54d0389b..33623bb16c 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -14,6 +14,8 @@ use crate::arch::aarch64::kernel::core_local::core_scheduler; pub use crate::arch::aarch64::kernel::interrupts; #[cfg(target_arch = "aarch64")] pub use crate::arch::aarch64::kernel::interrupts::wakeup_core; +#[cfg(all(target_arch = "aarch64", feature = "pci"))] +pub use crate::arch::aarch64::kernel::pci; #[cfg(target_arch = "aarch64")] pub use crate::arch::aarch64::kernel::processor; #[cfg(target_arch = "aarch64")] @@ -41,6 +43,8 @@ pub use crate::arch::x86_64::kernel::core_local; pub use crate::arch::x86_64::kernel::gdt::set_current_kernel_stack; #[cfg(target_arch = "x86_64")] pub use crate::arch::x86_64::kernel::interrupts; +#[cfg(all(target_arch = "x86_64", feature = "pci"))] +pub use crate::arch::x86_64::kernel::pci; #[cfg(target_arch = "x86_64")] pub use crate::arch::x86_64::kernel::processor; #[cfg(target_arch = "x86_64")] @@ -59,9 +63,9 @@ pub use crate::arch::x86_64::kernel::{ pub use crate::arch::x86_64::*; pub fn init_drivers() { - // Initialize PCI Drivers if on x86_64 + // Initialize PCI Drivers for x86_64 #[cfg(all(target_arch = "x86_64", feature = "pci"))] - crate::arch::x86_64::kernel::pci::init_drivers(); + crate::drivers::pci::init_drivers(); #[cfg(all(target_arch = "x86_64", not(feature = "pci")))] crate::arch::x86_64::kernel::mmio::init_drivers(); } diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs index 96102ff74d..b48773a1b7 100644 --- a/src/arch/x86_64/kernel/apic.rs +++ b/src/arch/x86_64/kernel/apic.rs @@ -204,7 +204,7 @@ impl fmt::Display for IoApicRecord { #[cfg(feature = "smp")] extern "x86-interrupt" fn tlb_flush_handler(_stack_frame: interrupts::ExceptionStackFrame) { debug!("Received TLB Flush Interrupt"); - increment_irq_counter(TLB_FLUSH_INTERRUPT_NUMBER.into()); + increment_irq_counter(TLB_FLUSH_INTERRUPT_NUMBER); unsafe { cr3_write(cr3()); } @@ -227,7 +227,7 @@ extern "x86-interrupt" fn spurious_interrupt_handler(stack_frame: interrupts::Ex #[cfg(feature = "smp")] extern "x86-interrupt" fn wakeup_handler(_stack_frame: interrupts::ExceptionStackFrame) { debug!("Received Wakeup Interrupt"); - increment_irq_counter(WAKEUP_INTERRUPT_NUMBER.into()); + increment_irq_counter(WAKEUP_INTERRUPT_NUMBER); let core_scheduler = core_scheduler(); core_scheduler.check_input(); eoi(); @@ -479,11 +479,11 @@ pub fn init() { idt[TLB_FLUSH_INTERRUPT_NUMBER as usize] .set_handler_fn(tlb_flush_handler) .set_stack_index(0); - interrupts::add_irq_name((TLB_FLUSH_INTERRUPT_NUMBER - 32).into(), "TLB flush"); + interrupts::add_irq_name(TLB_FLUSH_INTERRUPT_NUMBER - 32, "TLB flush"); idt[WAKEUP_INTERRUPT_NUMBER as usize] .set_handler_fn(wakeup_handler) .set_stack_index(0); - interrupts::add_irq_name((WAKEUP_INTERRUPT_NUMBER - 32).into(), "Wakeup"); + interrupts::add_irq_name(WAKEUP_INTERRUPT_NUMBER - 32, "Wakeup"); } } diff --git a/src/arch/x86_64/kernel/core_local.rs b/src/arch/x86_64/kernel/core_local.rs index b635a4b7fa..cac1920643 100644 --- a/src/arch/x86_64/kernel/core_local.rs +++ b/src/arch/x86_64/kernel/core_local.rs @@ -76,6 +76,6 @@ pub fn set_core_scheduler(scheduler: *mut PerCoreScheduler) { CoreLocal::get().scheduler.set(scheduler); } -pub fn increment_irq_counter(irq_no: usize) { +pub fn increment_irq_counter(irq_no: u8) { CoreLocal::get().irq_statistics.inc(irq_no); } diff --git a/src/arch/x86_64/kernel/interrupts.rs b/src/arch/x86_64/kernel/interrupts.rs index 56d88eb0a0..2b1fed484d 100644 --- a/src/arch/x86_64/kernel/interrupts.rs +++ b/src/arch/x86_64/kernel/interrupts.rs @@ -9,7 +9,7 @@ pub use x86_64::instructions::interrupts::{disable, enable, enable_and_hlt as en use x86_64::registers::control::Cr2; use x86_64::set_general_handler; pub use x86_64::structures::idt::InterruptStackFrame as ExceptionStackFrame; -use x86_64::structures::idt::{InterruptDescriptorTable, PageFaultErrorCode}; +use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; use crate::arch::x86_64::kernel::core_local::{core_scheduler, increment_irq_counter}; use crate::arch::x86_64::kernel::{apic, processor}; @@ -99,16 +99,23 @@ pub fn install() { .set_handler_fn(device_not_available_exception) .set_stack_index(0); } + + IRQ_NAMES.lock().insert(7, "FPU"); } #[no_mangle] -pub extern "C" fn irq_install_handler(irq_number: u32, handler: usize) { +pub extern "C" fn irq_install_handler( + irq_number: u8, + handler: extern "x86-interrupt" fn(InterruptStackFrame), +) { debug!("Install handler for interrupt {}", irq_number); let idt = unsafe { &mut *(&mut IDT as *mut _ as *mut InterruptDescriptorTable) }; unsafe { idt[(32 + irq_number) as usize] - .set_handler_addr(x86_64::VirtAddr::new(handler as u64)) + .set_handler_addr(x86_64::VirtAddr::new( + u64::try_from(handler as usize).unwrap(), + )) .set_stack_index(0); } } @@ -123,7 +130,7 @@ fn abort(stack_frame: ExceptionStackFrame, index: u8, error_code: Option) { fn unhandle(_stack_frame: ExceptionStackFrame, index: u8, _error_code: Option) { warn!("received unhandled irq {index}"); apic::eoi(); - increment_irq_counter(index.into()); + increment_irq_counter(index); } fn unknown(_stack_frame: ExceptionStackFrame, index: u8, _error_code: Option) { @@ -270,15 +277,15 @@ extern "x86-interrupt" fn virtualization_exception(stack_frame: ExceptionStackFr scheduler::abort(); } -static IRQ_NAMES: InterruptTicketMutex> = +static IRQ_NAMES: InterruptTicketMutex> = InterruptTicketMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0))); -pub fn add_irq_name(irq_number: u32, name: &'static str) { +pub fn add_irq_name(irq_number: u8, name: &'static str) { debug!("Register name \"{}\" for interrupt {}", name, irq_number); IRQ_NAMES.lock().insert(32 + irq_number, name); } -fn get_irq_name(irq_number: u32) -> Option<&'static str> { +fn get_irq_name(irq_number: u8) -> Option<&'static str> { IRQ_NAMES.lock().get(&irq_number).copied() } @@ -298,8 +305,8 @@ impl IrqStatistics { } } - pub fn inc(&self, pos: usize) { - self.counters[pos].fetch_add(1, Ordering::Relaxed); + pub fn inc(&self, pos: u8) { + self.counters[usize::from(pos)].fetch_add(1, Ordering::Relaxed); } } diff --git a/src/arch/x86_64/kernel/mmio.rs b/src/arch/x86_64/kernel/mmio.rs index 2a2eda0569..ce87f15a74 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -17,11 +17,11 @@ pub const MAGIC_VALUE: u32 = 0x74726976; pub const MMIO_START: usize = 0x00000000c0000000; pub const MMIO_END: usize = 0x00000000c0000fff; -const IRQ_NUMBER: u32 = 12; +const IRQ_NUMBER: u8 = 12; static mut MMIO_DRIVERS: Vec = Vec::new(); -pub enum MmioDriver { +pub(crate) enum MmioDriver { VirtioNet(InterruptTicketMutex), } @@ -116,7 +116,7 @@ pub fn detect_network() -> Result<&'static mut MmioRegisterLayout, &'static str> Err("Network card not found!") } -pub fn register_driver(drv: MmioDriver) { +pub(crate) fn register_driver(drv: MmioDriver) { unsafe { MMIO_DRIVERS.push(drv); } diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index 7eeec90588..d8f9cd536f 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -237,8 +237,6 @@ pub fn boot_processor_init() { if is_uhyve_with_pci() || !is_uhyve() { #[cfg(feature = "pci")] pci::init(); - #[cfg(feature = "pci")] - pci::print_information(); } if !env::is_uhyve() { #[cfg(feature = "acpi")] diff --git a/src/arch/x86_64/kernel/pci.rs b/src/arch/x86_64/kernel/pci.rs index 3685223038..60b5d5c076 100644 --- a/src/arch/x86_64/kernel/pci.rs +++ b/src/arch/x86_64/kernel/pci.rs @@ -1,510 +1,76 @@ -#![allow(dead_code)] +use core::{u32, u8}; -use alloc::vec::Vec; -use core::{fmt, u32, u8}; - -use hermit_sync::{without_interrupts, InterruptTicketMutex}; +use pci_types::{ConfigRegionAccess, PciAddress, PciHeader}; use x86::io::*; -use crate::arch::x86_64::mm::{PhysAddr, VirtAddr}; -use crate::drivers::fs::virtio_fs::VirtioFsDriver; -use crate::drivers::net::rtl8139::{self, RTL8139Driver}; -use crate::drivers::net::virtio_net::VirtioNetDriver; -use crate::drivers::net::NetworkInterface; -use crate::drivers::virtio::transport::pci as pci_virtio; -use crate::drivers::virtio::transport::pci::VirtioDriver; - -// TODO: should these be pub? currently needed since used in virtio.rs maybe use getter methods to be more flexible. -pub const PCI_MAX_BUS_NUMBER: u8 = 32; -pub const PCI_MAX_DEVICE_NUMBER: u8 = 32; - -pub const PCI_CONFIG_ADDRESS_PORT: u16 = 0xCF8; -pub const PCI_CONFIG_ADDRESS_ENABLE: u32 = 1 << 31; - -pub const PCI_CONFIG_DATA_PORT: u16 = 0xCFC; -pub const PCI_COMMAND_BUSMASTER: u32 = 1 << 2; - -pub const PCI_ID_REGISTER: u32 = 0x00; -pub const PCI_COMMAND_REGISTER: u32 = 0x04; -pub const PCI_CLASS_REGISTER: u32 = 0x08; -pub const PCI_HEADER_REGISTER: u32 = 0x0C; -pub const PCI_BAR0_REGISTER: u32 = 0x10; -pub const PCI_CAPABILITY_LIST_REGISTER: u32 = 0x34; -pub const PCI_INTERRUPT_REGISTER: u32 = 0x3C; - -pub const PCI_STATUS_CAPABILITIES_LIST: u32 = 1 << 4; - -pub const PCI_BASE_ADDRESS_IO_SPACE: u32 = 1 << 0; -pub const PCI_MEM_BASE_ADDRESS_64BIT: u32 = 1 << 2; -pub const PCI_MEM_PREFETCHABLE: u32 = 1 << 3; -pub const PCI_MEM_BASE_ADDRESS_MASK: u32 = 0xFFFF_FFF0; -pub const PCI_IO_BASE_ADDRESS_MASK: u32 = 0xFFFF_FFFC; +use crate::drivers::pci::{PciDevice, PCI_DEVICES}; -pub const PCI_HEADER_TYPE_MASK: u32 = 0x007F_0000; -pub const PCI_MULTIFUNCTION_MASK: u32 = 0x0080_0000; +const PCI_MAX_BUS_NUMBER: u8 = 32; +const PCI_MAX_DEVICE_NUMBER: u8 = 32; -pub const PCI_CAP_ID_VNDR: u32 = 0x09; +const PCI_CONFIG_ADDRESS_PORT: u16 = 0xCF8; +const PCI_CONFIG_ADDRESS_ENABLE: u32 = 1 << 31; -static mut PCI_ADAPTERS: Vec = Vec::new(); -static mut PCI_DRIVERS: Vec = Vec::new(); +const PCI_CONFIG_DATA_PORT: u16 = 0xCFC; -#[derive(Clone, Debug)] -pub struct PciAdapter { - pub bus: u8, - pub device: u8, - pub vendor_id: u16, - pub device_id: u16, - pub class_id: u8, - pub subclass_id: u8, - pub programming_interface_id: u8, - pub base_addresses: Vec, - pub irq: u8, -} -#[derive(Clone, Copy, Debug)] -pub enum PciBar { - IO(IOBar), - Memory(MemoryBar), -} -#[derive(Clone, Copy, Debug)] -pub struct IOBar { - pub index: u8, - pub addr: u32, - pub size: usize, -} -#[derive(Clone, Copy, Debug)] -pub struct MemoryBar { - pub index: u8, - pub addr: usize, - pub size: usize, - pub width: u8, // 32 or 64 bit - pub prefetchable: bool, -} +#[derive(Debug, Copy, Clone)] +pub(crate) struct PciConfigRegion; -#[allow(clippy::large_enum_variant)] -pub enum PciDriver { - VirtioFs(InterruptTicketMutex), - VirtioNet(InterruptTicketMutex), - RTL8139Net(InterruptTicketMutex), -} - -impl PciDriver { - fn get_network_driver(&self) -> Option<&InterruptTicketMutex> { - match self { - Self::VirtioNet(drv) => Some(drv), - Self::RTL8139Net(drv) => Some(drv), - _ => None, - } - } - - fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex> { - match self { - Self::VirtioFs(drv) => Some(drv), - _ => None, - } +impl PciConfigRegion { + pub const fn new() -> Self { + Self {} } } -pub fn register_driver(drv: PciDriver) { - unsafe { - PCI_DRIVERS.push(drv); - } -} - -pub fn get_network_driver() -> Option<&'static InterruptTicketMutex> { - unsafe { PCI_DRIVERS.iter().find_map(|drv| drv.get_network_driver()) } -} - -pub fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex> { - unsafe { - PCI_DRIVERS - .iter() - .find_map(|drv| drv.get_filesystem_driver()) - } -} - -/// Reads all bar registers of specified device and returns vector of PciBar's containing addresses and sizes. -fn parse_bars(bus: u8, device: u8, vendor_id: u16, device_id: u16) -> Vec { - let mut bar_idxs = 0..6; - let mut bars = Vec::new(); - while let Some(i) = bar_idxs.next() { - let register = PCI_BAR0_REGISTER + (i << 2); - let barword = read_config(bus, device, register); - debug!( - "Found bar{} @{:x}:{:x} as {:#x}", - i, vendor_id, device_id, barword - ); - - // We assume BIOS or something similar has initialized the device already and set appropriate values into the bar registers - - // If barword is all 0, the bar is disabled - if barword == 0 { - continue; - } - - // Determine if bar is IO-mapped or memory-mapped - if barword & PCI_BASE_ADDRESS_IO_SPACE != 0 { - // IO Mapped BAR - debug!("Bar {} @{:x}:{:x} IO mapped!", i, vendor_id, device_id); - - let base_addr = barword & PCI_IO_BASE_ADDRESS_MASK; - - // determine size by writing 0xFFFFFFFF - write_config(bus, device, register, u32::MAX); - let sizebits = read_config(bus, device, register); - // Restore original value of register - write_config(bus, device, register, barword); - let size = (!(sizebits & PCI_IO_BASE_ADDRESS_MASK) + 1) as usize; - - bars.push(PciBar::IO(IOBar { - index: i as u8, - addr: base_addr, - size, - })); - } else { - // Memory Mapped BAR - let prefetchable = barword & PCI_MEM_PREFETCHABLE != 0; - - if barword & PCI_MEM_BASE_ADDRESS_64BIT != 0 { - // 64-bit, load additional bar-word - let register_high = PCI_BAR0_REGISTER + (bar_idxs.next().unwrap() << 2); - let barword_high = read_config(bus, device, register_high); - - let base_addr = ((barword_high as usize) << 32) + (barword & 0xFFFF_FFF0) as usize; - debug!( - "64-bit memory bar, merged next barword. Addr: {:#x}", - base_addr - ); - - // determine size by writing 0xFFFFFFFF - write_config(bus, device, register, u32::MAX); - let sizebits = read_config(bus, device, register); - - // Also read/write to register_high if needed - let size = if sizebits == 0 { - write_config(bus, device, register_high, u32::MAX); - let sizebits = read_config(bus, device, register_high); - // Restore original value of register_high - write_config(bus, device, register_high, barword); - - ((!sizebits + 1) as usize) << 32 - } else { - (!(sizebits & PCI_MEM_BASE_ADDRESS_MASK) + 1) as usize - }; - - // Restore original value - write_config(bus, device, register, barword); - - bars.push(PciBar::Memory(MemoryBar { - index: i as u8, - addr: base_addr, - size, - width: 64, - prefetchable, - })); - } else { - // 32-bit - let base_addr = (barword & 0xFFFF_FFF0) as usize; - - // determine size by writing 0xFFFFFFFF - write_config(bus, device, register, u32::MAX); - let size = !(read_config(bus, device, register) & PCI_MEM_BASE_ADDRESS_MASK) + 1; - - // Restore original value - write_config(bus, device, register, barword); - - bars.push(PciBar::Memory(MemoryBar { - index: i as u8, - addr: base_addr, - size: size.try_into().unwrap(), - width: 32, - prefetchable, - })); - } - } - } - - bars -} - -impl PciAdapter { - fn new(bus: u8, device: u8, vendor_id: u16, device_id: u16) -> Option { - let header = read_config(bus, device, PCI_HEADER_REGISTER); - if header & PCI_HEADER_TYPE_MASK != 0 { - error!( - "PCI Device @{:x}:{:x} does not have header type 0!", - vendor_id, device_id - ); - return None; - } - if header & PCI_MULTIFUNCTION_MASK != 0 { - warn!( - "PCI Device @{:x}:{:x} has multiple functions! Currently only one is handled.", - vendor_id, device_id - ); - } - - let class_ids = read_config(bus, device, PCI_CLASS_REGISTER); - let bars = parse_bars(bus, device, vendor_id, device_id); - let interrupt_info = read_config(bus, device, PCI_INTERRUPT_REGISTER); - - Some(Self { - bus, - device, - vendor_id, - device_id, - class_id: (class_ids >> 24) as u8, - subclass_id: (class_ids >> 16) as u8, - programming_interface_id: (class_ids >> 8) as u8, - base_addresses: bars, - irq: interrupt_info as u8, - }) - } - - pub fn make_bus_master(&self) { - let mut command = read_config(self.bus, self.device, PCI_COMMAND_REGISTER); - command |= PCI_COMMAND_BUSMASTER; - write_config(self.bus, self.device, PCI_COMMAND_REGISTER, command); +impl ConfigRegionAccess for PciConfigRegion { + #[inline] + fn function_exists(&self, _address: PciAddress) -> bool { + true } - /// Returns the bar at bar-register baridx. - pub fn get_bar(&self, baridx: u8) -> Option { - for pci_bar in &self.base_addresses { - match pci_bar { - PciBar::IO(pci_bar) => { - if pci_bar.index == baridx { - return Some(PciBar::IO(*pci_bar)); - } - } - PciBar::Memory(pci_bar) => { - if pci_bar.index == baridx { - return Some(PciBar::Memory(*pci_bar)); - } - } - } + #[inline] + unsafe fn read(&self, pci_addr: PciAddress, register: u16) -> u32 { + let address = PCI_CONFIG_ADDRESS_ENABLE + | u32::from(pci_addr.bus()) << 16 + | u32::from(pci_addr.device()) << 11 + | u32::from(register); + unsafe { + outl(PCI_CONFIG_ADDRESS_PORT, address); + crate::drivers::pci::from_pci_endian(inl(PCI_CONFIG_DATA_PORT)) } - None } - /// Memory maps pci bar with specified index to identical location in virtual memory. - /// no_cache determines if we set the `Cache Disable` flag in the page-table-entry. - /// Returns (virtual-pointer, size) if successful, else None (if bar non-existent or IOSpace) - pub fn memory_map_bar(&self, index: u8, no_cache: bool) -> Option<(VirtAddr, usize)> { - let pci_bar = match self.get_bar(index) { - Some(PciBar::IO(_)) => { - warn!("Cannot map IOBar!"); - return None; - } - Some(PciBar::Memory(mem_bar)) => mem_bar, - None => { - warn!("Memory bar not found!"); - return None; - } - }; - - debug!( - "Mapping bar {} at {:#x} with length {:#x}", - index, pci_bar.addr, pci_bar.size - ); - - if pci_bar.width != 64 { - warn!("Currently only mapping of 64 bit bars is supported!"); - return None; - } - if !pci_bar.prefetchable { - warn!("Currently only mapping of prefetchable bars is supported!") + #[inline] + unsafe fn write(&self, pci_addr: PciAddress, register: u16, value: u32) { + let address = PCI_CONFIG_ADDRESS_ENABLE + | u32::from(pci_addr.bus()) << 16 + | u32::from(pci_addr.device()) << 11 + | u32::from(register); + unsafe { + outl(PCI_CONFIG_ADDRESS_PORT, address); + outl(PCI_CONFIG_DATA_PORT, value.to_le()); } - - // Since the bios/bootloader manages the physical address space, the address got from the bar is unique and not overlapping. - // We therefore do not need to reserve any additional memory in our kernel. - // Map bar into RW^X virtual memory - let physical_address = pci_bar.addr; - let virtual_address = crate::mm::map( - PhysAddr::from(physical_address), - pci_bar.size, - true, - false, - no_cache, - ); - - Some((virtual_address, pci_bar.size)) - } -} - -impl fmt::Display for PciBar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (typ, addr, size) = match self { - PciBar::IO(io_bar) => ("IOBar", io_bar.addr as usize, io_bar.size), - PciBar::Memory(mem_bar) => ("MemoryBar", mem_bar.addr, mem_bar.size), - }; - write!(f, "{typ}: {addr:#x} (size {size:#x})")?; - - Ok(()) - } -} - -impl fmt::Display for PciAdapter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(feature = "pci-ids")] - use pci_ids::{Class, Device, FromId, Subclass}; - - #[cfg(feature = "pci-ids")] - let class_name = Class::from_id(self.class_id).map_or("Unknown Class", |class| { - class - .subclasses() - .find(|s| s.id() == self.subclass_id) - .map(Subclass::name) - .unwrap_or_else(|| class.name()) - }); - - #[cfg(feature = "pci-ids")] - let (vendor_name, device_name) = Device::from_vid_pid(self.vendor_id, self.device_id) - .map(|device| (device.vendor().name(), device.name())) - .unwrap_or(("Unknown Vendor", "Unknown Device")); - - #[cfg(not(feature = "pci-ids"))] - let (class_name, vendor_name, device_name) = ("Unknown Class", "Unknown Vendor", "Unknown Device"); - - // Output detailed readable information about this device. - write!( - f, - "{:02X}:{:02X} {} [{:02X}{:02X}]: {} {} [{:04X}:{:04X}]", - self.bus, - self.device, - class_name, - self.class_id, - self.subclass_id, - vendor_name, - device_name, - self.vendor_id, - self.device_id - )?; - - // If the devices uses an IRQ, output this one as well. - if self.irq != 0 && self.irq != u8::MAX { - write!(f, ", IRQ {}", self.irq)?; - } - - for pci_bar in &self.base_addresses { - write!(f, ", {pci_bar}")?; - } - - Ok(()) } } -/// Returns the value (indicated by bus, device and register) of the pci -/// configuration space. -pub fn read_config(bus: u8, device: u8, register: u32) -> u32 { - let address = - PCI_CONFIG_ADDRESS_ENABLE | u32::from(bus) << 16 | u32::from(device) << 11 | register; - unsafe { - outl(PCI_CONFIG_ADDRESS_PORT, address); - inl(PCI_CONFIG_DATA_PORT) - } -} - -pub fn write_config(bus: u8, device: u8, register: u32, data: u32) { - let address = - PCI_CONFIG_ADDRESS_ENABLE | u32::from(bus) << 16 | u32::from(device) << 11 | register; - unsafe { - outl(PCI_CONFIG_ADDRESS_PORT, address); - outl(PCI_CONFIG_DATA_PORT, data); - } -} - -pub fn init() { +pub(crate) fn init() { debug!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1); // HermitCore only uses PCI for network devices. // Therefore, multifunction devices as well as additional bridges are not scanned. // We also limit scanning to the first 32 buses. + let pci_config = PciConfigRegion::new(); for bus in 0..PCI_MAX_BUS_NUMBER { for device in 0..PCI_MAX_DEVICE_NUMBER { - let device_vendor_id = read_config(bus, device, PCI_ID_REGISTER); - if device_vendor_id != u32::MAX { - let device_id = (device_vendor_id >> 16) as u16; - let vendor_id = device_vendor_id as u16; - let adapter = PciAdapter::new(bus, device, vendor_id, device_id); - if let Some(adapter) = adapter { - unsafe { - PCI_ADAPTERS.push(adapter); - } - } - } - } - } -} - -pub fn init_drivers() { - let mut nic_available = false; - - // virtio: 4.1.2 PCI Device Discovery - without_interrupts(|| { - for adapter in unsafe { - PCI_ADAPTERS - .iter() - .filter(|x| x.vendor_id == 0x1AF4 && x.device_id >= 0x1000 && x.device_id <= 0x107F) - } { - info!( - "Found virtio network device with device id {:#x}", - adapter.device_id - ); + let pci_address = PciAddress::new(0, bus, device, 0); + let header = PciHeader::new(pci_address); - match pci_virtio::init_device(adapter) { - Ok(VirtioDriver::Network(drv)) => { - nic_available = true; - register_driver(PciDriver::VirtioNet(InterruptTicketMutex::new(drv))) + let (device_id, vendor_id) = header.id(&pci_config); + if device_id != u16::MAX && vendor_id != u16::MAX { + unsafe { + PCI_DEVICES.push(PciDevice::new(pci_address, pci_config)); } - Ok(VirtioDriver::FileSystem(drv)) => { - register_driver(PciDriver::VirtioFs(InterruptTicketMutex::new(drv))) - } - _ => {} } } - - // do we already found a network interface? - if !nic_available { - // Searching for Realtek RTL8139, which is supported by Qemu - for adapter in unsafe { - PCI_ADAPTERS.iter().filter(|x| { - x.vendor_id == 0x10ec && x.device_id >= 0x8138 && x.device_id <= 0x8139 - }) - } { - info!( - "Found Realtek network device with device id {:#x}", - adapter.device_id - ); - - if let Ok(drv) = rtl8139::init_device(adapter) { - register_driver(PciDriver::RTL8139Net(InterruptTicketMutex::new(drv))) - } - } - } - }); -} - -pub fn print_information() { - infoheader!(" PCI BUS INFORMATION "); - - for adapter in unsafe { PCI_ADAPTERS.iter() } { - info!("{}", adapter); - } - - infofooter!(); -} - -/// A module containing PCI specific errors -/// -/// Errors include... -pub mod error { - /// An enum of PciErrors - /// typically carrying the device's id as an u16. - #[derive(Debug)] - pub enum PciError { - General(u16), - NoBar(u16), - NoCapPtr(u16), - BadCapPtr(u16), - NoVirtioCaps(u16), } } diff --git a/src/arch/x86_64/kernel/scheduler.rs b/src/arch/x86_64/kernel/scheduler.rs index ec8b3544d4..b05bf2d957 100644 --- a/src/arch/x86_64/kernel/scheduler.rs +++ b/src/arch/x86_64/kernel/scheduler.rs @@ -368,7 +368,7 @@ impl TaskFrame for Task { } extern "x86-interrupt" fn timer_handler(_stack_frame: interrupts::ExceptionStackFrame) { - increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER.into()); + increment_irq_counter(apic::TIMER_INTERRUPT_NUMBER); core_scheduler().handle_waiting_tasks(); apic::eoi(); core_scheduler().scheduler(); @@ -381,5 +381,5 @@ pub fn install_timer_handler() { .set_handler_fn(timer_handler) .set_stack_index(0); } - interrupts::add_irq_name((apic::TIMER_INTERRUPT_NUMBER - 32).into(), "Timer"); + interrupts::add_irq_name(apic::TIMER_INTERRUPT_NUMBER - 32, "Timer"); } diff --git a/src/drivers/fs/virtio_fs.rs b/src/drivers/fs/virtio_fs.rs index 84a376b908..507f55e22c 100644 --- a/src/drivers/fs/virtio_fs.rs +++ b/src/drivers/fs/virtio_fs.rs @@ -2,6 +2,8 @@ use alloc::rc::Rc; use alloc::string::{String, ToString}; use alloc::vec::Vec; +use pci_types::InterruptLine; + use self::constants::{FeatureSet, Features}; use crate::config::VIRTIO_MAX_QUEUE_SIZE; #[cfg(feature = "pci")] @@ -19,7 +21,7 @@ use crate::fs::fuse::{self, FuseInterface}; /// A wrapper struct for the raw configuration structure. /// Handling the right access to fields, as some are read-only /// for the driver. -pub struct FsDevCfg { +pub(crate) struct FsDevCfg { pub raw: &'static FsDevCfgRaw, pub dev_id: u16, pub features: FeatureSet, @@ -30,14 +32,14 @@ pub struct FsDevCfg { /// Struct allows to control devices virtqueues as also /// the device itself. #[allow(dead_code)] -pub struct VirtioFsDriver { +pub(crate) struct VirtioFsDriver { pub(super) dev_cfg: FsDevCfg, pub(super) com_cfg: ComCfg, pub(super) isr_stat: IsrStatus, pub(super) notif_cfg: NotifCfg, pub(super) vqueues: Vec>, pub(super) ready_queue: Vec, - pub(super) irq: u8, + pub(super) irq: InterruptLine, } // Backend-independent interface for Virtio network driver @@ -86,7 +88,7 @@ impl VirtioFsDriver { /// /// See Virtio specification v1.1. - 3.1.1. /// and v1.1. - 5.11.5 - pub fn init_dev(&mut self) -> Result<(), VirtioFsError> { + pub(crate) fn init_dev(&mut self) -> Result<(), VirtioFsError> { // Reset self.com_cfg.reset_dev(); diff --git a/src/drivers/fs/virtio_pci.rs b/src/drivers/fs/virtio_pci.rs index 60f3836368..f3a040f0ba 100644 --- a/src/drivers/fs/virtio_pci.rs +++ b/src/drivers/fs/virtio_pci.rs @@ -1,8 +1,9 @@ use alloc::vec::Vec; -use crate::arch::kernel::pci::PciAdapter; +use crate::arch::pci::PciConfigRegion; use crate::drivers::fs::virtio_fs::constants::FeatureSet; use crate::drivers::fs::virtio_fs::{FsDevCfg, VirtioFsDriver}; +use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; @@ -12,7 +13,7 @@ use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; /// #[derive(Debug, Copy, Clone)] #[repr(C)] -pub struct FsDevCfgRaw { +pub(crate) struct FsDevCfgRaw { /// Tag is the name associated with this file system. /// The tag is encoded in UTF-8 and padded with NUL bytes if shorter than the available space. /// This field is not NUL-terminated if the encoded bytes take up the entire field. @@ -63,13 +64,15 @@ impl VirtioFsDriver { /// configuration structures and moving them into the struct. pub fn new( mut caps_coll: UniCapsColl, - adapter: &PciAdapter, + device: &PciDevice, ) -> Result { + let device_id = device.device_id(); + let com_cfg = match caps_coll.get_com_cfg() { Some(com_cfg) => com_cfg, None => { error!("No common config. Aborting!"); - return Err(error::VirtioFsError::NoComCfg(adapter.device_id)); + return Err(error::VirtioFsError::NoComCfg(device_id)); } }; @@ -77,7 +80,7 @@ impl VirtioFsDriver { Some(isr_stat) => isr_stat, None => { error!("No ISR status config. Aborting!"); - return Err(error::VirtioFsError::NoIsrCfg(adapter.device_id)); + return Err(error::VirtioFsError::NoIsrCfg(device_id)); } }; @@ -85,7 +88,7 @@ impl VirtioFsDriver { Some(notif_cfg) => notif_cfg, None => { error!("No notif config. Aborting!"); - return Err(error::VirtioFsError::NoNotifCfg(adapter.device_id)); + return Err(error::VirtioFsError::NoNotifCfg(device_id)); } }; @@ -98,7 +101,7 @@ impl VirtioFsDriver { } None => { error!("No dev config. Aborting!"); - return Err(error::VirtioFsError::NoDevCfg(adapter.device_id)); + return Err(error::VirtioFsError::NoDevCfg(device_id)); } } }; @@ -110,14 +113,14 @@ impl VirtioFsDriver { notif_cfg, vqueues: Vec::new(), ready_queue: Vec::new(), - irq: adapter.irq, + irq: device.irq().unwrap(), }) } /// Initializes virtio filesystem device - pub fn init(adapter: &PciAdapter) -> Result { - let mut drv = match pci::map_caps(adapter) { - Ok(caps) => match VirtioFsDriver::new(caps, adapter) { + pub fn init(device: &PciDevice) -> Result { + let mut drv = match pci::map_caps(device) { + Ok(caps) => match VirtioFsDriver::new(caps, device) { Ok(driver) => driver, Err(fs_err) => { error!("Initializing new network driver failed. Aborting!"); diff --git a/src/drivers/mod.rs b/src/drivers/mod.rs index 6bc2671d00..6593a545d6 100644 --- a/src/drivers/mod.rs +++ b/src/drivers/mod.rs @@ -1,28 +1,25 @@ //! A module containing hermit-rs driver, hermit-rs driver trait and driver specific errors. -#[cfg(not(target_arch = "aarch64"))] pub mod fs; -#[cfg(not(target_arch = "aarch64"))] pub mod net; - -#[cfg(not(target_arch = "aarch64"))] +#[cfg(feature = "pci")] +pub mod pci; pub mod virtio; /// A common error module for drivers. /// [DriverError](enums.drivererror.html) values will be /// passed on to higher layers. -#[cfg(not(target_arch = "aarch64"))] pub mod error { use core::fmt; - #[cfg(feature = "pci")] + #[cfg(all(feature = "pci", not(target_arch = "aarch64")))] use crate::drivers::net::rtl8139::RTL8139Error; use crate::drivers::virtio::error::VirtioError; #[derive(Debug)] pub enum DriverError { InitVirtioDevFail(VirtioError), - #[cfg(feature = "pci")] + #[cfg(all(feature = "pci", not(target_arch = "aarch64")))] InitRTL8139DevFail(RTL8139Error), } @@ -32,7 +29,7 @@ pub mod error { } } - #[cfg(feature = "pci")] + #[cfg(all(feature = "pci", not(target_arch = "aarch64")))] impl From for DriverError { fn from(err: RTL8139Error) -> Self { DriverError::InitRTL8139DevFail(err) @@ -45,7 +42,7 @@ pub mod error { DriverError::InitVirtioDevFail(ref err) => { write!(f, "Virtio driver failed: {err:?}") } - #[cfg(feature = "pci")] + #[cfg(all(feature = "pci", not(target_arch = "aarch64")))] DriverError::InitRTL8139DevFail(ref err) => { write!(f, "RTL8139 driver failed: {err:?}") } diff --git a/src/drivers/net/mod.rs b/src/drivers/net/mod.rs index b31cfe13a1..dd622241f6 100644 --- a/src/drivers/net/mod.rs +++ b/src/drivers/net/mod.rs @@ -1,4 +1,4 @@ -#[cfg(feature = "pci")] +#[cfg(all(feature = "pci", not(target_arch = "aarch64")))] pub mod rtl8139; #[cfg(not(feature = "pci"))] pub mod virtio_mmio; @@ -8,13 +8,17 @@ pub mod virtio_pci; use alloc::vec::Vec; +#[cfg(target_arch = "x86_64")] use crate::arch::kernel::apic; use crate::arch::kernel::core_local::*; +#[cfg(target_arch = "x86_64")] use crate::arch::kernel::interrupts::ExceptionStackFrame; #[cfg(not(feature = "pci"))] use crate::arch::kernel::mmio as hardware; +#[cfg(target_arch = "aarch64")] +use crate::arch::scheduler::State; #[cfg(feature = "pci")] -use crate::arch::kernel::pci as hardware; +use crate::drivers::pci as hardware; /// A trait for accessing the network interface pub trait NetworkInterface { @@ -40,11 +44,8 @@ pub trait NetworkInterface { fn handle_interrupt(&mut self) -> bool; } -#[cfg(target_arch = "x86_64")] -pub extern "x86-interrupt" fn network_irqhandler(_stack_frame: ExceptionStackFrame) { - debug!("Receive network interrupt"); - apic::eoi(); - +#[inline] +fn _irqhandler() { let has_packet = if let Some(driver) = hardware::get_network_driver() { driver.lock().handle_interrupt() } else { @@ -59,3 +60,16 @@ pub extern "x86-interrupt" fn network_irqhandler(_stack_frame: ExceptionStackFra core_scheduler.scheduler(); } } + +#[cfg(target_arch = "aarch64")] +pub fn network_irqhandler(_state: &State) { + debug!("Receive network interrupt"); + _irqhandler(); +} + +#[cfg(target_arch = "x86_64")] +pub extern "x86-interrupt" fn network_irqhandler(_stack_frame: ExceptionStackFrame) { + debug!("Receive network interrupt"); + apic::eoi(); + _irqhandler(); +} diff --git a/src/drivers/net/rtl8139.rs b/src/drivers/net/rtl8139.rs index caee8546ab..2ac2b8153f 100644 --- a/src/drivers/net/rtl8139.rs +++ b/src/drivers/net/rtl8139.rs @@ -6,15 +6,17 @@ use alloc::boxed::Box; use alloc::vec::Vec; use core::mem; +use pci_types::{Bar, InterruptLine, MAX_BARS}; use x86::io::*; use crate::arch::kernel::core_local::increment_irq_counter; use crate::arch::kernel::interrupts::*; -use crate::arch::kernel::pci; use crate::arch::mm::paging::virt_to_phys; use crate::arch::mm::VirtAddr; +use crate::arch::pci::PciConfigRegion; use crate::drivers::error::DriverError; use crate::drivers::net::{network_irqhandler, NetworkInterface}; +use crate::drivers::pci::PciDevice; /// size of the receive buffer const RX_BUF_LEN: usize = 8192; @@ -199,10 +201,10 @@ pub enum RTL8139Error { /// /// Struct allows to control device queues as also /// the device itself. -pub struct RTL8139Driver { +pub(crate) struct RTL8139Driver { iobase: u16, mtu: u16, - irq: u8, + irq: InterruptLine, mac: [u8; 6], tx_in_use: [bool; NO_TX_BUFFERS], tx_counter: usize, @@ -328,7 +330,7 @@ impl NetworkInterface for RTL8139Driver { } fn handle_interrupt(&mut self) -> bool { - increment_irq_counter((32 + self.irq).into()); + increment_irq_counter(32 + self.irq); let isr_contents = unsafe { inw(self.iobase + ISR) }; @@ -429,23 +431,26 @@ impl Drop for RTL8139Driver { } } -pub fn init_device(adapter: &pci::PciAdapter) -> Result { - let mut iter = adapter.base_addresses.iter().filter_map(|&x| match x { - pci::PciBar::IO(base) => Some(base.addr), - _ => None, - }); - let iobase: u16 = iter - .next() +pub(crate) fn init_device( + device: &PciDevice, +) -> Result { + let irq = device.irq().unwrap(); + let mut iobase: Option = None; + + for i in 0..MAX_BARS { + if let Some(Bar::Io { port }) = device.bar(i.try_into().unwrap()) { + iobase = Some(port) + } + } + + let iobase: u16 = iobase .ok_or(DriverError::InitRTL8139DevFail(RTL8139Error::Unknown))? .try_into() .unwrap(); - debug!( - "Found RTL8139 at iobase {:#x} (irq {})", - iobase, adapter.irq - ); + debug!("Found RTL8139 at iobase {:#x} (irq {})", iobase, irq); - adapter.make_bus_master(); + device.make_bus_master(); let mac: [u8; 6] = unsafe { [ @@ -579,14 +584,14 @@ pub fn init_device(adapter: &pci::PciAdapter) -> Result Result { - if let Ok(mut drv) = VirtioNetDriver::new(dev_id, registers, irq_no.try_into().unwrap()) { + if let Ok(mut drv) = VirtioNetDriver::new(dev_id, registers, irq_no) { match drv.init_dev() { Err(error_code) => Err(VirtioError::NetDriver(error_code)), _ => { diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs index 37b83f6d54..aad5a1a761 100644 --- a/src/drivers/net/virtio_net.rs +++ b/src/drivers/net/virtio_net.rs @@ -11,6 +11,7 @@ use core::cmp::Ordering; use core::mem; use core::result::Result; +use pci_types::InterruptLine; use zerocopy::AsBytes; use self::constants::{FeatureSet, Features, NetHdrGSO, Status, MAX_NUM_VQ}; @@ -35,7 +36,7 @@ pub const ETH_HDR: usize = 14usize; /// A wrapper struct for the raw configuration structure. /// Handling the right access to fields, as some are read-only /// for the driver. -pub struct NetDevCfg { +pub(crate) struct NetDevCfg { pub raw: &'static NetDevCfgRaw, pub dev_id: u16, @@ -486,7 +487,7 @@ impl TxQueues { /// /// Struct allows to control devices virtqueues as also /// the device itself. -pub struct VirtioNetDriver { +pub(crate) struct VirtioNetDriver { pub(super) dev_cfg: NetDevCfg, pub(super) com_cfg: ComCfg, pub(super) isr_stat: IsrStatus, @@ -497,7 +498,7 @@ pub struct VirtioNetDriver { pub(super) send_vqs: TxQueues, pub(super) num_vqs: u16, - pub(super) irq: u8, + pub(super) irq: InterruptLine, pub(super) polling_mode_counter: u32, } @@ -654,7 +655,7 @@ impl NetworkInterface for VirtioNetDriver { } fn handle_interrupt(&mut self) -> bool { - increment_irq_counter((32 + self.irq).into()); + increment_irq_counter(32 + self.irq); let result = if self.isr_stat.is_interrupt() { true diff --git a/src/drivers/net/virtio_pci.rs b/src/drivers/net/virtio_pci.rs index 3c2c0ad60c..2fa3a05472 100644 --- a/src/drivers/net/virtio_pci.rs +++ b/src/drivers/net/virtio_pci.rs @@ -7,9 +7,10 @@ use alloc::rc::Rc; use alloc::vec::Vec; use core::cell::RefCell; -use crate::arch::kernel::pci::PciAdapter; +use crate::arch::pci::PciConfigRegion; use crate::drivers::net::virtio_net::constants::FeatureSet; use crate::drivers::net::virtio_net::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver}; +use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; @@ -19,7 +20,7 @@ use crate::drivers::virtio::virtqueue::Virtq; /// See specification v1.1. - 5.1.4 /// #[repr(C)] -pub struct NetDevCfgRaw { +pub(crate) struct NetDevCfgRaw { // Specifies Mac address, only Valid if VIRTIO_NET_F_MAC is set mac: [u8; 6], // Indicates status of device. Only valid if VIRTIO_NET_F_STATUS is set @@ -86,15 +87,16 @@ impl VirtioNetDriver { /// Instantiates a new (VirtioNetDriver)[VirtioNetDriver] struct, by checking the available /// configuration structures and moving them into the struct. - pub fn new( + pub(crate) fn new( mut caps_coll: UniCapsColl, - adapter: &PciAdapter, + device: &PciDevice, ) -> Result { + let device_id = device.device_id(); let com_cfg = match caps_coll.get_com_cfg() { Some(com_cfg) => com_cfg, None => { error!("No common config. Aborting!"); - return Err(error::VirtioNetError::NoComCfg(adapter.device_id)); + return Err(error::VirtioNetError::NoComCfg(device_id)); } }; @@ -102,7 +104,7 @@ impl VirtioNetDriver { Some(isr_stat) => isr_stat, None => { error!("No ISR status config. Aborting!"); - return Err(error::VirtioNetError::NoIsrCfg(adapter.device_id)); + return Err(error::VirtioNetError::NoIsrCfg(device_id)); } }; @@ -110,7 +112,7 @@ impl VirtioNetDriver { Some(notif_cfg) => notif_cfg, None => { error!("No notif config. Aborting!"); - return Err(error::VirtioNetError::NoNotifCfg(adapter.device_id)); + return Err(error::VirtioNetError::NoNotifCfg(device_id)); } }; @@ -123,7 +125,7 @@ impl VirtioNetDriver { } None => { error!("No dev config. Aborting!"); - return Err(error::VirtioNetError::NoDevCfg(adapter.device_id)); + return Err(error::VirtioNetError::NoDevCfg(device_id)); } } }; @@ -147,7 +149,7 @@ impl VirtioNetDriver { false, ), num_vqs: 0, - irq: adapter.irq, + irq: device.irq().unwrap(), polling_mode_counter: 0, }) } @@ -160,9 +162,11 @@ impl VirtioNetDriver { /// /// Returns a driver instance of /// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html). - pub fn init(adapter: &PciAdapter) -> Result { - let mut drv = match pci::map_caps(adapter) { - Ok(caps) => match VirtioNetDriver::new(caps, adapter) { + pub(crate) fn init( + device: &PciDevice, + ) -> Result { + let mut drv = match pci::map_caps(device) { + Ok(caps) => match VirtioNetDriver::new(caps, device) { Ok(driver) => driver, Err(vnet_err) => { error!("Initializing new network driver failed. Aborting!"); diff --git a/src/drivers/pci.rs b/src/drivers/pci.rs new file mode 100644 index 0000000000..94cef8d441 --- /dev/null +++ b/src/drivers/pci.rs @@ -0,0 +1,466 @@ +#![allow(dead_code)] + +use alloc::vec::Vec; +use core::fmt; + +use hermit_sync::{without_interrupts, InterruptTicketMutex}; +use pci_types::{ + Bar, ConfigRegionAccess, DeviceId, EndpointHeader, InterruptLine, PciAddress, PciHeader, + VendorId, MAX_BARS, +}; + +use crate::arch::mm::{PhysAddr, VirtAddr}; +use crate::arch::pci::PciConfigRegion; +use crate::drivers::fs::virtio_fs::VirtioFsDriver; +#[cfg(not(target_arch = "aarch64"))] +use crate::drivers::net::rtl8139::{self, RTL8139Driver}; +use crate::drivers::net::virtio_net::VirtioNetDriver; +use crate::drivers::net::NetworkInterface; +use crate::drivers::virtio::transport::pci as pci_virtio; +use crate::drivers::virtio::transport::pci::VirtioDriver; + +/// Converts a given little endian coded u32 to native endian coded. +// +// INFO: As the endianness received from the device is little endian coded +// the given value must be swapped again on big endian machines. Which is done +// via the u32::to_le() method as the u32::to_be() would be a no-op in big endian +// machines. Resulting in no conversion. +#[inline] +pub(crate) fn from_pci_endian(val: u32) -> u32 { + if cfg!(target = "big_endian") { + val.to_le() + } else { + val + } +} + +/// The module contains constants specific to PCI. +#[allow(dead_code)] +pub(crate) mod constants { + // PCI constants + pub(crate) const PCI_MAX_BUS_NUMBER: u8 = 32; + pub(crate) const PCI_MAX_DEVICE_NUMBER: u8 = 32; + pub(crate) const PCI_CONFIG_ADDRESS_PORT: u16 = 0xCF8; + pub(crate) const PCI_CONFIG_ADDRESS_ENABLE: u32 = 1 << 31; + pub(crate) const PCI_CONFIG_DATA_PORT: u16 = 0xCFC; + pub(crate) const PCI_CAP_ID_VNDR_VIRTIO: u32 = 0x09; + pub(crate) const PCI_MASK_IS_DEV_BUS_MASTER: u32 = 0x0000_0004u32; + pub(crate) const PCI_COMMAND_BUSMASTER: u32 = 1 << 2; + + /// PCI registers offset inside header, + /// if PCI header is of type 00h. + #[allow(dead_code, non_camel_case_types)] + #[repr(u16)] + pub enum RegisterHeader { + PCI_ID_REGISTER = 0x00u16, + PCI_COMMAND_REGISTER = 0x04u16, + PCI_CLASS_REGISTER = 0x08u16, + PCI_HEADER_REGISTER = 0x0Cu16, + PCI_BAR0_REGISTER = 0x10u16, + PCI_CAPABILITY_LIST_REGISTER = 0x34u16, + PCI_INTERRUPT_REGISTER = 0x3Cu16, + } + + impl From for u16 { + fn from(val: RegisterHeader) -> u16 { + match val { + RegisterHeader::PCI_ID_REGISTER => 0x00u16, + RegisterHeader::PCI_COMMAND_REGISTER => 0x04u16, + RegisterHeader::PCI_CLASS_REGISTER => 0x08u16, + RegisterHeader::PCI_HEADER_REGISTER => 0x0Cu16, + RegisterHeader::PCI_BAR0_REGISTER => 0x10u16, + RegisterHeader::PCI_CAPABILITY_LIST_REGISTER => 0x34u16, + RegisterHeader::PCI_INTERRUPT_REGISTER => 0x3Cu16, + } + } + } + + /// PCI masks. For convenience put into an enum and provides + /// an `Into` method for usage. + #[allow(dead_code, non_camel_case_types)] + #[repr(u32)] + pub enum Masks { + PCI_MASK_IS_BAR_IO_BAR = 0x0000_0001u32, + PCI_MASK_IS_MEM_BASE_ADDRESS_64BIT = 0x0000_0004u32, + PCI_MASK_IS_MEM_BAR_PREFETCHABLE = 0x0000_0008u32, + PCI_MASK_STATUS_CAPABILITIES_LIST = 0x0000_0010u32, + PCI_MASK_CAPLIST_POINTER = 0x0000_00FCu32, + PCI_MASK_HEADER_TYPE = 0x007F_0000u32, + PCI_MASK_MULTIFUNCTION = 0x0080_0000u32, + PCI_MASK_MEM_BASE_ADDRESS = 0xFFFF_FFF0u32, + PCI_MASK_IO_BASE_ADDRESS = 0xFFFF_FFFCu32, + } + + impl From for u32 { + fn from(val: Masks) -> u32 { + match val { + Masks::PCI_MASK_STATUS_CAPABILITIES_LIST => 0x0000_0010u32, + Masks::PCI_MASK_CAPLIST_POINTER => 0x0000_00FCu32, + Masks::PCI_MASK_HEADER_TYPE => 0x007F_0000u32, + Masks::PCI_MASK_MULTIFUNCTION => 0x0080_0000u32, + Masks::PCI_MASK_MEM_BASE_ADDRESS => 0xFFFF_FFF0u32, + Masks::PCI_MASK_IO_BASE_ADDRESS => 0xFFFF_FFFCu32, + Masks::PCI_MASK_IS_MEM_BAR_PREFETCHABLE => 0x0000_0008u32, + Masks::PCI_MASK_IS_MEM_BASE_ADDRESS_64BIT => 0x0000_0004u32, + Masks::PCI_MASK_IS_BAR_IO_BAR => 0x0000_0001u32, + } + } + } +} + +pub(crate) static mut PCI_DEVICES: Vec> = Vec::new(); +static mut PCI_DRIVERS: Vec = Vec::new(); + +#[derive(Copy, Clone, Debug)] +pub(crate) struct PciDevice { + address: PciAddress, + access: T, +} + +impl PciDevice { + pub const fn new(address: PciAddress, access: T) -> Self { + Self { address, access } + } + + pub fn read_register(&self, register: u16) -> u32 { + unsafe { self.access.read(self.address, register) } + } + + pub fn write_register(&self, register: u16, value: u32) { + unsafe { self.access.write(self.address, register, value) } + } + + pub fn make_bus_master(&self) { + use crate::drivers::pci::constants::{RegisterHeader, PCI_COMMAND_BUSMASTER}; + + unsafe { + let mut command = self + .access + .read(self.address, RegisterHeader::PCI_COMMAND_REGISTER.into()); + command |= PCI_COMMAND_BUSMASTER; + self.access.write( + self.address, + RegisterHeader::PCI_COMMAND_REGISTER.into(), + command, + ) + } + } + + /// Returns the bar at bar-register `slot`. + pub fn bar(&self, slot: u8) -> Option { + let header = PciHeader::new(self.address); + if let Some(endpoint) = EndpointHeader::from_header(header, &self.access) { + return endpoint.bar(slot, &self.access); + } + + None + } + + /// Memory maps pci bar with specified index to identical location in virtual memory. + /// no_cache determines if we set the `Cache Disable` flag in the page-table-entry. + /// Returns (virtual-pointer, size) if successful, else None (if bar non-existent or IOSpace) + pub fn memory_map_bar(&self, index: u8, no_cache: bool) -> Option<(VirtAddr, usize)> { + let (address, size, prefetchable, width) = match self.bar(index) { + Some(Bar::Io { .. }) => { + warn!("Cannot map IOBar!"); + return None; + } + Some(Bar::Memory32 { + address, + size, + prefetchable, + }) => ( + u64::from(address), + usize::try_from(size).unwrap(), + prefetchable, + 32, + ), + Some(Bar::Memory64 { + address, + size, + prefetchable, + }) => (address, usize::try_from(size).unwrap(), prefetchable, 64), + _ => { + return None; + } + }; + + debug!( + "Mapping bar {} at {:#x} with length {:#x}", + index, address, size + ); + + if width != 64 { + warn!("Currently only mapping of 64 bit bars is supported!"); + return None; + } + if !prefetchable { + warn!("Currently only mapping of prefetchable bars is supported!") + } + + // Since the bios/bootloader manages the physical address space, the address got from the bar is unique and not overlapping. + // We therefore do not need to reserve any additional memory in our kernel. + // Map bar into RW^X virtual memory + let physical_address = address; + let virtual_address = crate::mm::map( + PhysAddr::from(physical_address), + size, + true, + false, + no_cache, + ); + + Some((virtual_address, size)) + } + + pub fn irq(&self) -> Option { + let header = PciHeader::new(self.address); + if let Some(endpoint) = EndpointHeader::from_header(header, &self.access) { + let (_pin, line) = endpoint.interrupt(&self.access); + Some(line) + } else { + None + } + } + + pub fn bus(&self) -> u8 { + self.address.bus() + } + + pub fn device(&self) -> u8 { + self.address.device() + } + + pub fn vendor_id(&self) -> VendorId { + let header = PciHeader::new(self.address); + let (vendor_id, _device_id) = header.id(&self.access); + vendor_id + } + + pub fn device_id(&self) -> DeviceId { + let header = PciHeader::new(self.address); + let (_vendor_id, device_id) = header.id(&self.access); + device_id + } + + pub fn id(&self) -> (VendorId, DeviceId) { + let header = PciHeader::new(self.address); + header.id(&self.access) + } +} + +impl fmt::Display for PciDevice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let header = PciHeader::new(self.address); + let header_type = header.header_type(&self.access); + let (vendor_id, device_id) = header.id(&self.access); + let (_dev_rev, class_id, subclass_id, _interface) = header.revision_and_class(&self.access); + + if let Some(endpoint) = EndpointHeader::from_header(header, &self.access) { + #[cfg(feature = "pci-ids")] + let (class_name, vendor_name, device_name) = { + use pci_ids::{Class, Device, FromId, Subclass}; + + let class_name = Class::from_id(class_id).map_or("Unknown Class", |class| { + class + .subclasses() + .find(|s| s.id() == subclass_id) + .map(Subclass::name) + .unwrap_or_else(|| class.name()) + }); + + let (vendor_name, device_name) = Device::from_vid_pid(vendor_id, device_id) + .map(|device| (device.vendor().name(), device.name())) + .unwrap_or(("Unknown Vendor", "Unknown Device")); + + (class_name, vendor_name, device_name) + }; + + #[cfg(not(feature = "pci-ids"))] + let (class_name, vendor_name, device_name) = ("Unknown Class", "Unknown Vendor", "Unknown Device"); + + // Output detailed readable information about this device. + write!( + f, + "{:02X}:{:02X} {} [{:02X}{:02X}]: {} {} [{:04X}:{:04X}]", + self.address.bus(), + self.address.device(), + class_name, + class_id, + subclass_id, + vendor_name, + device_name, + vendor_id, + device_id + )?; + + // If the devices uses an IRQ, output this one as well. + let (_, irq) = endpoint.interrupt(&self.access); + if irq != 0 && irq != u8::MAX { + write!(f, ", IRQ {}", irq)?; + } + + let mut slot: u8 = 0; + while usize::from(slot) < MAX_BARS { + if let Some(pci_bar) = endpoint.bar(slot, &self.access) { + match pci_bar { + Bar::Memory64 { + address, + size, + prefetchable, + } => { + write!(f, ", BAR{} Memory64 {{ address: {:#X}, size: {:#X}, prefetchable: {} }}", slot, address, size, prefetchable)?; + slot += 1; + } + Bar::Memory32 { + address, + size, + prefetchable, + } => { + write!(f, ", BAR{} Memory32 {{ address: {:#X}, size: {:#X}, prefetchable: {} }}", slot, address, size, prefetchable)?; + } + Bar::Io { port } => { + write!(f, ", BAR{} IO {{ port: {:#X} }}", slot, port)?; + } + } + } + slot += 1; + } + } else { + // Output detailed readable information about this device. + write!( + f, + "{:02X}:{:02X} {:?} [{:04X}:{:04X}]", + self.address.bus(), + self.address.device(), + header_type, + vendor_id, + device_id + )?; + } + + Ok(()) + } +} + +pub(crate) fn print_information() { + infoheader!(" PCI BUS INFORMATION "); + + for adapter in unsafe { PCI_DEVICES.iter() } { + info!("{}", adapter); + } + + infofooter!(); +} + +#[allow(clippy::large_enum_variant)] +pub(crate) enum PciDriver { + VirtioFs(InterruptTicketMutex), + VirtioNet(InterruptTicketMutex), + #[cfg(not(target_arch = "aarch64"))] + RTL8139Net(InterruptTicketMutex), +} + +impl PciDriver { + fn get_network_driver(&self) -> Option<&InterruptTicketMutex> { + match self { + Self::VirtioNet(drv) => Some(drv), + #[cfg(not(target_arch = "aarch64"))] + Self::RTL8139Net(drv) => Some(drv), + _ => None, + } + } + + fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex> { + match self { + Self::VirtioFs(drv) => Some(drv), + _ => None, + } + } +} + +pub(crate) fn register_driver(drv: PciDriver) { + unsafe { + PCI_DRIVERS.push(drv); + } +} + +pub(crate) fn get_network_driver() -> Option<&'static InterruptTicketMutex> { + unsafe { PCI_DRIVERS.iter().find_map(|drv| drv.get_network_driver()) } +} + +pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex> { + unsafe { + PCI_DRIVERS + .iter() + .find_map(|drv| drv.get_filesystem_driver()) + } +} + +#[cfg(not(target_arch = "aarch64"))] +pub(crate) fn init_drivers() { + let mut nic_available = false; + + // virtio: 4.1.2 PCI Device Discovery + without_interrupts(|| { + for adapter in unsafe { + PCI_DEVICES.iter().filter(|x| { + let (vendor_id, device_id) = x.id(); + vendor_id == 0x1AF4 && (0x1000..=0x107F).contains(&device_id) + }) + } { + info!( + "Found virtio network device with device id {:#x}", + adapter.device_id() + ); + + match pci_virtio::init_device(adapter) { + Ok(VirtioDriver::Network(drv)) => { + nic_available = true; + register_driver(PciDriver::VirtioNet(InterruptTicketMutex::new(drv))) + } + Ok(VirtioDriver::FileSystem(drv)) => { + register_driver(PciDriver::VirtioFs(InterruptTicketMutex::new(drv))) + } + _ => {} + } + } + + // do we already found a network interface? + #[cfg(not(target_arch = "aarch64"))] + if !nic_available { + // Searching for Realtek RTL8139, which is supported by Qemu + for adapter in unsafe { + PCI_DEVICES.iter().filter(|x| { + let (vendor_id, device_id) = x.id(); + vendor_id == 0x10ec && (0x8138..=0x8139).contains(&device_id) + }) + } { + info!( + "Found Realtek network device with device id {:#x}", + adapter.device_id() + ); + + if let Ok(drv) = rtl8139::init_device(adapter) { + register_driver(PciDriver::RTL8139Net(InterruptTicketMutex::new(drv))) + } + } + } + }); +} + +/// A module containing PCI specific errors +/// +/// Errors include... +pub(crate) mod error { + /// An enum of PciErrors + /// typically carrying the device's id as an u16. + #[derive(Debug)] + pub enum PciError { + General(u16), + NoBar(u16), + NoCapPtr(u16), + BadCapPtr(u16), + NoVirtioCaps(u16), + } +} diff --git a/src/drivers/virtio/env.rs b/src/drivers/virtio/env.rs index ca2b3ac5c7..9ac754c5f4 100644 --- a/src/drivers/virtio/env.rs +++ b/src/drivers/virtio/env.rs @@ -181,50 +181,15 @@ pub mod pci { use alloc::vec::Vec; use core::result::Result; - use crate::arch::x86_64::kernel::pci; - use crate::arch::x86_64::kernel::pci::error::PciError; - use crate::arch::x86_64::kernel::pci::{PciAdapter, PciBar}; - use crate::arch::x86_64::mm::PhysAddr; + use pci_types::{Bar, MAX_BARS}; + + use crate::arch::mm::PhysAddr; + use crate::arch::pci::PciConfigRegion; + use crate::drivers::pci::error::PciError; + use crate::drivers::pci::PciDevice; use crate::drivers::virtio::env::memory::VirtMemAddr; use crate::drivers::virtio::transport::pci::PciBar as VirtioPciBar; - /// Wrapper function to read the configuration space of a PCI - /// device at the given register. Returns the registers value. - pub fn read_config(adapter: &PciAdapter, register: u32) -> u32 { - from_pci_endian(pci::read_config( - adapter.bus, - adapter.device, - register.to_le(), - )) - } - - /// Wrapper function to read the configuration space of a PCI - /// device at the given register. Returns the registers value. - pub fn read_cfg_no_adapter(bus: u8, device: u8, register: u32) -> u32 { - from_pci_endian(pci::read_config(bus, device, register.to_le())) - } - - /// Wrapper function to write the configuration space of a PCI - /// device at the given register. - #[allow(dead_code)] - pub fn write_config(adapter: &PciAdapter, register: u32, data: u32) { - pci::write_config(adapter.bus, adapter.device, register.to_le(), data.to_le()); - } - - /// Converts a given little endian coded u32 to native endian coded. - // - // INFO: As the endianness received from the device is little endian coded - // the given value must be swapped again on big endian machines. Which is done - // via the u32::to_le() method as the u32::to_be() would be a no-op in big endian - // machines. Resulting in no conversion. - fn from_pci_endian(val: u32) -> u32 { - if cfg!(target = "big_endian") { - val.to_le() - } else { - val - } - } - /// Maps all memory areas indicated by the devices BAR's into /// Virtual address space. /// @@ -233,44 +198,55 @@ pub mod pci { /// /// WARN: Currently unsafely casts kernel::PciBar.size (usize) to an /// u64 - pub fn map_bar_mem(adapter: &PciAdapter) -> Result, PciError> { + pub(crate) fn map_bar_mem( + device: &PciDevice, + ) -> Result, PciError> { let mut mapped_bars: Vec = Vec::new(); - for bar in &adapter.base_addresses { - match bar { - PciBar::IO(_) => { + for i in 0..MAX_BARS { + match device.bar(i.try_into().unwrap()) { + Some(Bar::Io { .. }) => { warn!("Cannot map I/O BAR!"); continue; } - PciBar::Memory(bar) => { - if bar.width != 64 { - warn!("Currently only mapping of 64 bit BAR's is supported!"); - continue; - } - if !bar.prefetchable { + Some(Bar::Memory64 { + address, + size, + prefetchable, + }) => { + if !prefetchable { warn!("Currently only mapping of prefetchable BAR's is supported!"); continue; } let virtual_address = VirtMemAddr::from( - crate::mm::map(PhysAddr::from(bar.addr), bar.size, true, true, true).0, + crate::mm::map( + PhysAddr::from(address), + size.try_into().unwrap(), + true, + true, + true, + ) + .0, ); mapped_bars.push(VirtioPciBar::new( - bar.index, + i.try_into().unwrap(), virtual_address, - bar.size as u64, + size, )); } + Some(Bar::Memory32 { .. }) => { + warn!("Currently only mapping of 64 bit BAR's is supported!"); + } + _ => {} } } if mapped_bars.is_empty() { - error!( - "No correct memory BAR for device {:x} found.", - adapter.device_id - ); - Err(PciError::NoBar(adapter.device_id)) + let device_id = device.device_id(); + error!("No correct memory BAR for device {:x} found.", device_id); + Err(PciError::NoBar(device_id)) } else { Ok(mapped_bars) } diff --git a/src/drivers/virtio/mod.rs b/src/drivers/virtio/mod.rs index 7013e4d431..a700166404 100644 --- a/src/drivers/virtio/mod.rs +++ b/src/drivers/virtio/mod.rs @@ -8,11 +8,11 @@ pub mod virtqueue; pub mod error { use core::fmt; - #[cfg(feature = "pci")] - use crate::arch::x86_64::kernel::pci::error::PciError; #[cfg(feature = "pci")] pub use crate::drivers::fs::virtio_fs::error::VirtioFsError; pub use crate::drivers::net::virtio_net::error::VirtioNetError; + #[cfg(feature = "pci")] + use crate::drivers::pci::error::PciError; #[derive(Debug)] pub enum VirtioError { diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 30f1398fdf..cc868bab03 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -9,8 +9,8 @@ use core::result::Result; use core::sync::atomic::{fence, Ordering}; use core::u8; +use crate::arch::kernel::interrupts::*; use crate::arch::mm::PhysAddr; -use crate::arch::x86_64::kernel::interrupts::*; use crate::drivers::error::DriverError; use crate::drivers::net::network_irqhandler; use crate::drivers::net::virtio_net::VirtioNetDriver; @@ -343,13 +343,13 @@ struct IsrStatusRaw { interrupt_ack: u32, } -pub enum VirtioDriver { +pub(crate) enum VirtioDriver { Network(VirtioNetDriver), } -pub fn init_device( +pub(crate) fn init_device( registers: &'static mut MmioRegisterLayout, - irq_no: u32, + irq_no: u8, ) -> Result { let dev_id: u16 = 0; @@ -367,7 +367,7 @@ pub fn init_device( Ok(virt_net_drv) => { info!("Virtio network driver initialized."); // Install interrupt handler - irq_install_handler(irq_no, network_irqhandler as usize); + irq_install_handler(irq_no, network_irqhandler); add_irq_name(irq_no, "virtio_net"); Ok(VirtioDriver::Network(virt_net_drv)) diff --git a/src/drivers/virtio/transport/pci.rs b/src/drivers/virtio/transport/pci.rs index 97c2385733..7503d5c8da 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -7,17 +7,18 @@ use alloc::vec::Vec; use core::mem; use core::result::Result; -use crate::arch::kernel::pci::error::PciError; -use crate::arch::kernel::pci::PciAdapter; +use crate::arch::kernel::interrupts::*; use crate::arch::mm::PhysAddr; -use crate::arch::x86_64::kernel::interrupts::*; +use crate::arch::pci::PciConfigRegion; use crate::drivers::error::DriverError; use crate::drivers::fs::virtio_fs::VirtioFsDriver; use crate::drivers::net::network_irqhandler; use crate::drivers::net::virtio_net::VirtioNetDriver; +use crate::drivers::pci::error::PciError; +use crate::drivers::pci::PciDevice; +use crate::drivers::virtio::device; use crate::drivers::virtio::env::memory::{MemLen, MemOff, VirtMemAddr}; use crate::drivers::virtio::error::VirtioError; -use crate::drivers::virtio::{device, env}; /// Virtio device ID's /// See Virtio specification v1.1. - 5 @@ -129,8 +130,6 @@ impl From for CfgType { #[derive(Clone)] pub struct Origin { cfg_ptr: u32, // Register to be read to reach configuration structure of type cfg_type - dev: u8, // PCI device this configuration comes from - bus: u8, // Bus of the PCI device dev_id: u16, cap_struct: PciCapRaw, } @@ -184,6 +183,7 @@ pub struct PciCap { id: u8, offset: MemOff, length: MemLen, + device: PciDevice, // Following field can be used to retrieve original structure // from the config space. Needed by some structures and f // device specific configs. @@ -634,10 +634,8 @@ impl NotifCfg { // Assumes the cap_len is a multiple of 8 // This read MIGHT be slow, as it does NOT ensure 32 bit alignment. - let notify_off_multiplier = env::pci::read_cfg_no_adapter( - cap.origin.bus, - cap.origin.dev, - cap.origin.cfg_ptr + u32::from(cap.origin.cap_struct.cap_len), + let notify_off_multiplier = cap.device.read_register( + u16::try_from(cap.origin.cfg_ptr).unwrap() + u16::from(cap.origin.cap_struct.cap_len), ); // define base memory address from which the actual Queue Notify address can be derived via @@ -882,10 +880,8 @@ impl ShMemCfg { // Assumes the cap_len is a multiple of 8 // This read MIGHT be slow, as it does NOT ensure 32 bit alignment. - let offset_high = env::pci::read_cfg_no_adapter( - cap.origin.bus, - cap.origin.bus, - cap.origin.cfg_ptr + u32::from(cap.origin.cap_struct.cap_len), + let offset_high = cap.device.read_register( + u16::try_from(cap.origin.cfg_ptr).unwrap() + u16::from(cap.origin.cap_struct.cap_len), ); // Create 64 bit offset from high and low 32 bit values @@ -894,10 +890,9 @@ impl ShMemCfg { // Assumes the cap_len is a multiple of 8 // This read MIGHT be slow, as it does NOT ensure 32 bit alignment. - let length_high = env::pci::read_cfg_no_adapter( - cap.origin.bus, - cap.origin.bus, - cap.origin.cfg_ptr + u32::from(cap.origin.cap_struct.cap_len + 4), + let length_high = cap.device.read_register( + u16::try_from(cap.origin.cfg_ptr).unwrap() + + u16::from(cap.origin.cap_struct.cap_len + 4), ); // Create 64 bit length from high and low 32 bit values @@ -987,7 +982,7 @@ impl PciBar { } /// Reads a raw capability struct [PciCapRaw](structs.PcicapRaw.html) out of a PCI device's configuration space. -fn read_cap_raw(adapter: &PciAdapter, register: u32) -> PciCapRaw { +fn read_cap_raw(device: &PciDevice, register: u32) -> PciCapRaw { let mut quadruple_word: [u8; 16] = [0; 16]; debug!("Converting read word from PCI device config space into native endian bytes."); @@ -996,7 +991,9 @@ fn read_cap_raw(adapter: &PciAdapter, register: u32) -> PciCapRaw { for i in 0..4 { // Read word need to be converted to little endian bytes as PCI is little endian. // Interpretation of multi byte values needs to be swapped for big endian machines - let word: [u8; 4] = env::pci::read_config(adapter, register + 4 * i).to_le_bytes(); + let word: [u8; 4] = device + .read_register((register + 4 * i).try_into().unwrap()) + .to_le_bytes(); let i = 4 * i as usize; quadruple_word[i..i + 4].copy_from_slice(&word); } @@ -1021,14 +1018,18 @@ fn read_cap_raw(adapter: &PciAdapter, register: u32) -> PciCapRaw { /// /// Returns ONLY Virtio specific capabilities, which allow to locate the actual capability /// structures inside the memory areas, indicated by the BaseAddressRegisters (BAR's). -fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, PciError> { - let ptr: u32 = dev_caps_ptr(adapter); +fn read_caps( + device: &PciDevice, + bars: Vec, +) -> Result, PciError> { + let device_id = device.device_id(); + let ptr: u32 = dev_caps_ptr(device); // Checks if pointer is well formed and does not point into config header space let mut next_ptr = if ptr >= 0x40u32 { ptr } else { - return Err(PciError::BadCapPtr(adapter.device_id)); + return Err(PciError::BadCapPtr(device_id)); }; let mut cap_list: Vec = Vec::new(); @@ -1040,12 +1041,12 @@ fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, Pci // and only returns correct values if both reads // return equal values. // For clarity see Virtio specification v1.1. - 2.4.1 - let mut before = read_cap_raw(adapter, next_ptr); - let mut cap_raw = read_cap_raw(adapter, next_ptr); + let mut before = read_cap_raw(device, next_ptr); + let mut cap_raw = read_cap_raw(device, next_ptr); while before != cap_raw { - before = read_cap_raw(adapter, next_ptr); - cap_raw = read_cap_raw(adapter, next_ptr); + before = read_cap_raw(device, next_ptr); + cap_raw = read_cap_raw(device, next_ptr); } let mut iter = bars.iter(); @@ -1068,7 +1069,7 @@ fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, Pci } None => { error!("Found virtio capability whose BAR is not mapped or non existing. Capability of type {:x} and id {:x} for device {:x}, can not be used!", - cap_raw.cfg_type, cap_raw.id, adapter.device_id); + cap_raw.cfg_type, cap_raw.id, device_id); continue 'cap_list; } @@ -1081,11 +1082,10 @@ fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, Pci id: cap_raw.id, offset: MemOff::from(cap_raw.offset), length: MemLen::from(cap_raw.length), + device: *device, origin: Origin { cfg_ptr: next_ptr, - dev: adapter.device, - bus: adapter.bus, - dev_id: adapter.device_id, + dev_id: device_id, cap_struct: cap_raw, }, }) @@ -1098,11 +1098,8 @@ fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, Pci } if cap_list.is_empty() { - error!( - "No virtio capability found for device {:x}", - adapter.device_id - ); - Err(PciError::NoVirtioCaps(adapter.device_id)) + error!("No virtio capability found for device {:x}", device_id); + Err(PciError::NoVirtioCaps(device_id)) } else { Ok(cap_list) } @@ -1110,34 +1107,33 @@ fn read_caps(adapter: &PciAdapter, bars: Vec) -> Result, Pci /// Wrapper function to get a devices current status. /// As the device is not static, return value is not static. -fn dev_status(adapter: &PciAdapter) -> u32 { +fn dev_status(device: &PciDevice) -> u32 { // reads register 01 from PCU Header of type 00H. WHich is the Status(16bit) and Command(16bit) register - let stat_com_reg = env::pci::read_config( - adapter, - u32::from(constants::RegisterHeader00H::PCI_COMMAND_REGISTER), - ); + let stat_com_reg = device + .read_register(crate::drivers::pci::constants::RegisterHeader::PCI_COMMAND_REGISTER.into()); stat_com_reg >> 16 } /// Wrapper function to get a devices capabilities list pointer, which represents /// an offset starting from the header of the device's configuration space. -fn dev_caps_ptr(adapter: &PciAdapter) -> u32 { - let cap_lst_reg = env::pci::read_config( - adapter, - u32::from(constants::RegisterHeader00H::PCI_CAPABILITY_LIST_REGISTER), +fn dev_caps_ptr(device: &PciDevice) -> u32 { + let cap_lst_reg = device.read_register( + crate::drivers::pci::constants::RegisterHeader::PCI_CAPABILITY_LIST_REGISTER.into(), ); - cap_lst_reg & u32::from(constants::Masks::PCI_MASK_CAPLIST_POINTER) + cap_lst_reg & u32::from(crate::drivers::pci::constants::Masks::PCI_MASK_CAPLIST_POINTER) } /// Maps memory areas indicated by devices BAR's into virtual address space. -fn map_bars(adapter: &PciAdapter) -> Result, PciError> { - crate::drivers::virtio::env::pci::map_bar_mem(adapter) +fn map_bars(device: &PciDevice) -> Result, PciError> { + crate::drivers::virtio::env::pci::map_bar_mem(device) } /// Checks if the status of the device inidactes the device is using the /// capabilities pointer and therefore defines a capabiites list. -fn no_cap_list(adapter: &PciAdapter) -> bool { - dev_status(adapter) & u32::from(constants::Masks::PCI_MASK_STATUS_CAPABILITIES_LIST) == 0 +fn no_cap_list(device: &PciDevice) -> bool { + dev_status(device) + & u32::from(crate::drivers::pci::constants::Masks::PCI_MASK_STATUS_CAPABILITIES_LIST) + == 0 } /// Checks if minimal set of capabilities is present. @@ -1152,21 +1148,23 @@ fn check_caps(caps: UniCapsColl) -> Result { Ok(caps) } -pub fn map_caps(adapter: &PciAdapter) -> Result { +pub(crate) fn map_caps(device: &PciDevice) -> Result { + let device_id = device.device_id(); + // In case caplist pointer is not used, abort as it is essential - if no_cap_list(adapter) { + if no_cap_list(device) { error!("Found virtio device without capability list. Aborting!"); - return Err(PciError::NoCapPtr(adapter.device_id)); + return Err(PciError::NoCapPtr(device_id)); } // Mapped memory areas are reachable through PciBar structs. - let bar_list = match map_bars(adapter) { + let bar_list = match map_bars(device) { Ok(list) => list, Err(pci_error) => return Err(pci_error), }; // Get list of PciCaps pointing to capabilities - let cap_list = match read_caps(adapter, bar_list) { + let cap_list = match read_caps(device, bar_list) { Ok(list) => list, Err(pci_error) => return Err(pci_error), }; @@ -1179,21 +1177,21 @@ pub fn map_caps(adapter: &PciAdapter) -> Result { Some(cap) => caps.add_cfg_common(ComCfg::new(cap, pci_cap.id)), None => error!( "Common config capability with id {}, of device {:x}, could not be mapped!", - pci_cap.id, adapter.device_id + pci_cap.id, device_id ), }, CfgType::VIRTIO_PCI_CAP_NOTIFY_CFG => match NotifCfg::new(&pci_cap) { Some(notif) => caps.add_cfg_notif(notif), None => error!( "Notification config capability with id {}, of device {:x} could not be used!", - pci_cap.id, adapter.device_id + pci_cap.id, device_id ), }, CfgType::VIRTIO_PCI_CAP_ISR_CFG => match IsrStatusRaw::map(&pci_cap) { Some(isr_stat) => caps.add_cfg_isr(IsrStatus::new(isr_stat, pci_cap.id)), None => error!( "ISR status config capability with id {}, of device {:x} could not be used!", - pci_cap.id, adapter.device_id + pci_cap.id, device_id ), }, CfgType::VIRTIO_PCI_CAP_PCI_CFG => caps.add_cfg_alt(PciCfgAlt::new(&pci_cap)), @@ -1201,7 +1199,7 @@ pub fn map_caps(adapter: &PciAdapter) -> Result { Some(sh_mem) => caps.add_cfg_sh_mem(sh_mem), None => error!( "Shared Memory config capability with id {}, of device {:x} could not be used!", - pci_cap.id, adapter.device_id + pci_cap.id, device_id ), }, CfgType::VIRTIO_PCI_CAP_DEVICE_CFG => caps.add_cfg_dev(pci_cap), @@ -1218,8 +1216,12 @@ pub fn map_caps(adapter: &PciAdapter) -> Result { /// Checks existing drivers for support of given device. Upon match, provides /// driver with a [Caplist](struct.Caplist.html) struct, holding the structures of the capabilities /// list of the given device. -pub fn init_device(adapter: &PciAdapter) -> Result { - let virt_drv = match DevId::from(adapter.device_id) { +pub(crate) fn init_device( + device: &PciDevice, +) -> Result { + let device_id = device.device_id(); + + let virt_drv = match DevId::from(device_id) { DevId::VIRTIO_TRANS_DEV_ID_NET | DevId::VIRTIO_TRANS_DEV_ID_BLK | DevId::VIRTIO_TRANS_DEV_ID_MEM_BALL @@ -1229,15 +1231,15 @@ pub fn init_device(adapter: &PciAdapter) -> Result { | DevId::VIRTIO_TRANS_DEV_ID_9P => { warn!( "Legacy/transitional Virtio device, with id: {:#x} is NOT supported, skipping!", - adapter.device_id + device_id ); // Return Driver error inidacting device is not supported Err(DriverError::InitVirtioDevFail( - VirtioError::DevNotSupported(adapter.device_id), + VirtioError::DevNotSupported(device_id), )) } - DevId::VIRTIO_DEV_ID_NET => match VirtioNetDriver::init(adapter) { + DevId::VIRTIO_DEV_ID_NET => match VirtioNetDriver::init(device) { Ok(virt_net_drv) => { info!("Virtio network driver initialized."); Ok(VirtioDriver::Network(virt_net_drv)) @@ -1245,7 +1247,7 @@ pub fn init_device(adapter: &PciAdapter) -> Result { Err(virtio_error) => { error!( "Virtio networkd driver could not be initialized with device: {:x}", - adapter.device_id + device_id ); Err(DriverError::InitVirtioDevFail(virtio_error)) } @@ -1253,7 +1255,7 @@ pub fn init_device(adapter: &PciAdapter) -> Result { DevId::VIRTIO_DEV_ID_FS => { // TODO: check subclass // TODO: proper error handling on driver creation fail - match VirtioFsDriver::init(adapter) { + match VirtioFsDriver::init(device) { Ok(virt_fs_drv) => { info!("Virtio filesystem driver initialized."); Ok(VirtioDriver::FileSystem(virt_fs_drv)) @@ -1261,7 +1263,7 @@ pub fn init_device(adapter: &PciAdapter) -> Result { Err(virtio_error) => { error!( "Virtio filesystem driver could not be initialized with device: {:x}", - adapter.device_id + device_id ); Err(DriverError::InitVirtioDevFail(virtio_error)) } @@ -1270,12 +1272,12 @@ pub fn init_device(adapter: &PciAdapter) -> Result { _ => { warn!( "Virtio device with id: {:#x} is NOT supported, skipping!", - adapter.device_id + device_id ); // Return Driver error inidacting device is not supported Err(DriverError::InitVirtioDevFail( - VirtioError::DevNotSupported(adapter.device_id), + VirtioError::DevNotSupported(device_id), )) } }; @@ -1284,10 +1286,11 @@ pub fn init_device(adapter: &PciAdapter) -> Result { Ok(drv) => { match &drv { VirtioDriver::Network(_) => { - info!("Install virtio interrupt handler at line {}", adapter.irq); + let irq = device.irq().unwrap(); + info!("Install virtio interrupt handler at line {}", irq); // Install interrupt handler - irq_install_handler(adapter.irq as u32, network_irqhandler as usize); - add_irq_name(adapter.irq as u32, "virtio_net"); + irq_install_handler(irq, network_irqhandler); + add_irq_name(irq, "virtio_net"); Ok(drv) } @@ -1298,79 +1301,7 @@ pub fn init_device(adapter: &PciAdapter) -> Result { } } -pub enum VirtioDriver { +pub(crate) enum VirtioDriver { Network(VirtioNetDriver), FileSystem(VirtioFsDriver), } -/// The module contains constants specific to PCI. -#[allow(dead_code)] -pub mod constants { - // PCI constants - pub const PCI_MAX_BUS_NUMBER: u8 = 32; - pub const PCI_MAX_DEVICE_NUMBER: u8 = 32; - pub const PCI_CONFIG_ADDRESS_PORT: u16 = 0xCF8; - pub const PCI_CONFIG_ADDRESS_ENABLE: u32 = 1 << 31; - pub const PCI_CONFIG_DATA_PORT: u16 = 0xCFC; - pub const PCI_CAP_ID_VNDR_VIRTIO: u32 = 0x09; - pub const PCI_MASK_IS_DEV_BUS_MASTER: u32 = 0x0000_0004u32; - - /// PCI registers offset inside header, - /// if PCI header is of type 00h. - #[allow(dead_code, non_camel_case_types)] - #[repr(u32)] - pub enum RegisterHeader00H { - PCI_ID_REGISTER = 0x00u32, - PCI_COMMAND_REGISTER = 0x04u32, - PCI_CLASS_REGISTER = 0x08u32, - PCI_HEADER_REGISTER = 0x0Cu32, - PCI_BAR0_REGISTER = 0x10u32, - PCI_CAPABILITY_LIST_REGISTER = 0x34u32, - PCI_INTERRUPT_REGISTER = 0x3Cu32, - } - - impl From for u32 { - fn from(val: RegisterHeader00H) -> u32 { - match val { - RegisterHeader00H::PCI_ID_REGISTER => 0x00u32, - RegisterHeader00H::PCI_COMMAND_REGISTER => 0x04u32, - RegisterHeader00H::PCI_CLASS_REGISTER => 0x08u32, - RegisterHeader00H::PCI_HEADER_REGISTER => 0x0Cu32, - RegisterHeader00H::PCI_BAR0_REGISTER => 0x10u32, - RegisterHeader00H::PCI_CAPABILITY_LIST_REGISTER => 0x34u32, - RegisterHeader00H::PCI_INTERRUPT_REGISTER => 0x3Cu32, - } - } - } - - /// PCI masks. For convenience put into an enum and provides - /// an `Into` method for usage. - #[allow(dead_code, non_camel_case_types)] - #[repr(u32)] - pub enum Masks { - PCI_MASK_IS_BAR_IO_BAR = 0x0000_0001u32, - PCI_MASK_IS_MEM_BASE_ADDRESS_64BIT = 0x0000_0004u32, - PCI_MASK_IS_MEM_BAR_PREFETCHABLE = 0x0000_0008u32, - PCI_MASK_STATUS_CAPABILITIES_LIST = 0x0000_0010u32, - PCI_MASK_CAPLIST_POINTER = 0x0000_00FCu32, - PCI_MASK_HEADER_TYPE = 0x007F_0000u32, - PCI_MASK_MULTIFUNCTION = 0x0080_0000u32, - PCI_MASK_MEM_BASE_ADDRESS = 0xFFFF_FFF0u32, - PCI_MASK_IO_BASE_ADDRESS = 0xFFFF_FFFCu32, - } - - impl From for u32 { - fn from(val: Masks) -> u32 { - match val { - Masks::PCI_MASK_STATUS_CAPABILITIES_LIST => 0x0000_0010u32, - Masks::PCI_MASK_CAPLIST_POINTER => 0x0000_00FCu32, - Masks::PCI_MASK_HEADER_TYPE => 0x007F_0000u32, - Masks::PCI_MASK_MULTIFUNCTION => 0x0080_0000u32, - Masks::PCI_MASK_MEM_BASE_ADDRESS => 0xFFFF_FFF0u32, - Masks::PCI_MASK_IO_BASE_ADDRESS => 0xFFFF_FFFCu32, - Masks::PCI_MASK_IS_MEM_BAR_PREFETCHABLE => 0x0000_0008u32, - Masks::PCI_MASK_IS_MEM_BASE_ADDRESS_64BIT => 0x0000_0004u32, - Masks::PCI_MASK_IS_BAR_IO_BAR => 0x0000_0001u32, - } - } - } -} diff --git a/src/fs/fuse.rs b/src/fs/fuse.rs index 2e7fe8d110..9d2f19b446 100644 --- a/src/fs/fuse.rs +++ b/src/fs/fuse.rs @@ -8,7 +8,7 @@ use core::{fmt, u32, u8}; #[cfg(not(feature = "pci"))] use crate::arch::kernel::mmio::get_filesystem_driver; #[cfg(feature = "pci")] -use crate::arch::kernel::pci::get_filesystem_driver; +use crate::drivers::pci::get_filesystem_driver; use crate::drivers::virtio::virtqueue::AsSliceU8; use crate::syscalls::fs::{self, FileError, FilePerms, PosixFile, PosixFileSystem, SeekWhence}; diff --git a/src/fs/mod.rs b/src/fs/mod.rs index 4948ad527f..9ed3bc59c6 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -1,7 +1,7 @@ -#[cfg(all(feature = "pci", target_arch = "x86_64"))] +#[cfg(all(feature = "pci"))] pub mod fuse; pub fn init() { - #[cfg(all(feature = "pci", target_arch = "x86_64"))] + #[cfg(all(feature = "pci"))] fuse::init(); } diff --git a/src/lib.rs b/src/lib.rs index 9d72767459..af74179cf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,6 +54,7 @@ use qemu_exit::QEMUExit; pub(crate) use crate::arch::*; pub(crate) use crate::config::*; +use crate::kernel::is_uhyve_with_pci; pub use crate::syscalls::*; #[macro_use] @@ -336,6 +337,11 @@ fn boot_processor_main() -> ! { #[cfg(feature = "smp")] info!("Compiled with SMP support"); + if is_uhyve_with_pci() || !env::is_uhyve() { + #[cfg(feature = "pci")] + crate::drivers::pci::print_information(); + } + // Start the initd task. scheduler::PerCoreScheduler::spawn(initd, 0, scheduler::task::NORMAL_PRIO, 0, USER_STACK_SIZE); diff --git a/src/net/device.rs b/src/net/device.rs index 1dea481325..df7c7d5017 100644 --- a/src/net/device.rs +++ b/src/net/device.rs @@ -17,7 +17,7 @@ use crate::arch; #[cfg(not(feature = "pci"))] use crate::arch::kernel::mmio as hardware; #[cfg(feature = "pci")] -use crate::arch::kernel::pci as hardware; +use crate::drivers::pci as hardware; #[cfg(not(feature = "dhcpv4"))] use crate::env; use crate::net::{NetworkInterface, NetworkState}; diff --git a/src/net/executor.rs b/src/net/executor.rs index a5f52812e2..bb59121d17 100644 --- a/src/net/executor.rs +++ b/src/net/executor.rs @@ -19,7 +19,7 @@ static QUEUE: InterruptTicketMutex> = InterruptTicketMutex::new(Ve #[inline] fn set_polling_mode(value: bool) { #[cfg(feature = "pci")] - if let Some(driver) = crate::arch::kernel::pci::get_network_driver() { + if let Some(driver) = crate::drivers::pci::get_network_driver() { driver.lock().set_polling_mode(value) } } diff --git a/src/net/mod.rs b/src/net/mod.rs index d07ff8622c..dcea8f74e7 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -51,12 +51,29 @@ pub(crate) struct NetworkInterface<'a> { dhcp_handle: SocketHandle, } +#[cfg(target_arch = "x86_64")] fn start_endpoint() -> u16 { ((unsafe { core::arch::x86_64::_rdtsc() }) % (u16::MAX as u64)) .try_into() .unwrap() } +#[cfg(target_arch = "aarch64")] +fn start_endpoint() -> u16 { + use core::arch::asm; + let value: u64; + + unsafe { + asm!( + "mrs {value}, cntpct_el0", + value = out(reg) value, + options(nostack), + ); + } + + (value % (u16::MAX as u64)).try_into().unwrap() +} + #[inline] pub(crate) fn now() -> Instant { let microseconds = arch::processor::get_timer_ticks() + arch::get_boot_time();