refactor: fix kernel warnings
This commit is contained in:
parent
309c5c3e9f
commit
f88ca9b6d9
@ -1,3 +1,4 @@
|
||||
//! x86-64 implementation of ACPI management interfaces
|
||||
use core::{
|
||||
alloc::{AllocError, Allocator, GlobalAlloc, Layout},
|
||||
ptr::NonNull,
|
||||
@ -30,8 +31,10 @@ use crate::{
|
||||
use super::intrinsics;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[doc(hidden)]
|
||||
pub struct AcpiAllocator;
|
||||
#[derive(Clone, Copy)]
|
||||
#[doc(hidden)]
|
||||
pub struct AcpiHandlerImpl;
|
||||
struct SciHandler;
|
||||
|
||||
@ -328,7 +331,7 @@ impl aml::Handler for AcpiHandlerImpl {
|
||||
fn write_ec_u8(&self, _address: u64, _value: u8) {}
|
||||
|
||||
fn sleep(&self, duration: Duration) {
|
||||
todo!()
|
||||
util::polling_sleep(duration).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,6 +359,7 @@ impl AcpiHandler for AcpiHandlerImpl {
|
||||
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
|
||||
}
|
||||
|
||||
/// Initializes ACPI management
|
||||
pub fn init_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<(), Error> {
|
||||
let mut system = AcpiSystem::new(tables, Box::new(AcpiHandlerImpl)).unwrap();
|
||||
|
||||
|
@ -4,8 +4,7 @@ use core::{arch::global_asm, mem::size_of_val};
|
||||
use abi::{arch::SavedFrame, primitive_enum, process::Signal};
|
||||
|
||||
use crate::{
|
||||
arch::{x86_64::apic, CpuMessage},
|
||||
panic,
|
||||
arch::x86_64::apic,
|
||||
task::{context::TaskFrame, process::Process, Cpu},
|
||||
};
|
||||
|
||||
|
@ -64,6 +64,11 @@ impl IoPortAccess<u32> for IoPort<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a byte from the I/O port
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn inb(port: u16) -> u8 {
|
||||
let value: u8;
|
||||
@ -71,6 +76,11 @@ pub unsafe fn inb(port: u16) -> u8 {
|
||||
value
|
||||
}
|
||||
|
||||
/// Reads a 16-bit value from the I/O port
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn inw(port: u16) -> u16 {
|
||||
let value: u16;
|
||||
@ -78,6 +88,11 @@ pub unsafe fn inw(port: u16) -> u16 {
|
||||
value
|
||||
}
|
||||
|
||||
/// Reads a 32-bit value from the I/O port
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn inl(port: u16) -> u32 {
|
||||
let value: u32;
|
||||
@ -85,16 +100,31 @@ pub unsafe fn inl(port: u16) -> u32 {
|
||||
value
|
||||
}
|
||||
|
||||
/// Writes a byte to the I/O port.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outb(port: u16, value: u8) {
|
||||
core::arch::asm!("outb %al, %dx", in("dx") port, in("al") value, options(att_syntax));
|
||||
}
|
||||
|
||||
/// Writes a 16-bit value to the I/O port.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outw(port: u16, value: u16) {
|
||||
core::arch::asm!("outw %ax, %dx", in("dx") port, in("ax") value, options(att_syntax));
|
||||
}
|
||||
|
||||
/// Writes a 32-bit value to the I/O port.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Provides direct access to port I/O, unsafe.
|
||||
#[inline]
|
||||
pub unsafe fn outl(port: u16, value: u32) {
|
||||
core::arch::asm!("outl %eax, %dx", in("dx") port, in("eax") value, options(att_syntax));
|
||||
|
@ -1,8 +1,8 @@
|
||||
//! x86-64 architecture and platform implementation
|
||||
use core::{ptr::NonNull, sync::atomic::Ordering};
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use abi::error::Error;
|
||||
use acpi_lib::{mcfg::Mcfg, AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping};
|
||||
use acpi_lib::{mcfg::Mcfg, AcpiTables, HpetInfo, InterruptModel};
|
||||
use alloc::boxed::Box;
|
||||
use cpu::Cpu;
|
||||
use device_api::{
|
||||
|
@ -184,7 +184,7 @@ impl Device for Hpet {
|
||||
unsafe fn init_irq(&'static self) -> Result<(), Error> {
|
||||
// Configure timer 0
|
||||
let intc = ARCHITECTURE.external_interrupt_controller();
|
||||
let mut inner = self.inner.lock();
|
||||
let inner = self.inner.lock();
|
||||
|
||||
let tim0 = &inner.regs.Timers[0];
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
//! PCI/PCIe bus interfaces
|
||||
use core::fmt;
|
||||
|
||||
use acpi_lib::mcfg::McfgEntry;
|
||||
use alloc::{rc::Rc, vec::Vec};
|
||||
use bitflags::bitflags;
|
||||
use device_api::Device;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
@ -13,41 +15,64 @@ pub use space::{
|
||||
|
||||
use crate::sync::IrqSafeSpinlock;
|
||||
|
||||
pub const PCI_COMMAND_IO: u16 = 1 << 0;
|
||||
pub const PCI_COMMAND_MEMORY: u16 = 1 << 1;
|
||||
pub const PCI_COMMAND_BUS_MASTER: u16 = 1 << 2;
|
||||
pub const PCI_COMMAND_INTERRUPT_DISABLE: u16 = 1 << 10;
|
||||
bitflags! {
|
||||
/// Command register of the PCI configuration space
|
||||
pub struct PciCommandRegister: u16 {
|
||||
/// If set, I/O access to the device is enabled
|
||||
const ENABLE_IO = 1 << 0;
|
||||
/// If set, memory-mapped access to the device is enabled
|
||||
const ENABLE_MEMORY = 1 << 1;
|
||||
/// If set, the device can generate PCI bus accesses on its own
|
||||
const BUS_MASTER = 1 << 2;
|
||||
/// If set, interrupts are masked from being raised
|
||||
const DISABLE_INTERRUPTS = 1 << 10;
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the address of a single object on a bus (or the bus itself)
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct PciAddress {
|
||||
/// PCIe segment group, ignored (?) with PCI
|
||||
pub segment: u8,
|
||||
/// Bus number
|
||||
pub bus: u8,
|
||||
/// Slot/device number
|
||||
pub device: u8,
|
||||
/// Function number
|
||||
pub function: u8,
|
||||
}
|
||||
|
||||
// TODO other attributes
|
||||
/// Address provided by PCI configuration space Base Address Register
|
||||
#[derive(Debug)]
|
||||
pub enum PciBaseAddress {
|
||||
/// 32/64-bit memory address
|
||||
Memory(usize),
|
||||
/// I/O space address
|
||||
Io(u16),
|
||||
}
|
||||
|
||||
/// Describes a PCI device
|
||||
#[derive(Debug)]
|
||||
pub struct PciDeviceInfo {
|
||||
/// Address of the device
|
||||
pub address: PciAddress,
|
||||
/// Configuration space access method
|
||||
pub config_space: PciConfigSpace,
|
||||
}
|
||||
|
||||
/// Interface for "taking" PCI devices from the bus
|
||||
pub trait FromPciBus: Sized {
|
||||
/// Constructs an instance of a driver for the device using the information provided
|
||||
fn from_pci_bus(info: &PciDeviceInfo) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
/// Used to store PCI bus devices which were enumerated by the kernel
|
||||
pub struct PciBusDevice {
|
||||
info: PciDeviceInfo,
|
||||
driver: Option<Rc<dyn Device>>,
|
||||
}
|
||||
|
||||
/// Represents a single PCIe bus segment
|
||||
pub struct PciBusSegment {
|
||||
segment_number: u8,
|
||||
bus_number_start: u8,
|
||||
@ -57,6 +82,7 @@ pub struct PciBusSegment {
|
||||
devices: Vec<PciBusDevice>,
|
||||
}
|
||||
|
||||
/// Manager struct to store and control all PCI devices in the system
|
||||
pub struct PciBusManager {
|
||||
segments: Vec<PciBusSegment>,
|
||||
}
|
||||
@ -117,6 +143,7 @@ impl PciBusSegment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enumerates the bus segment, placing found devices into the manager
|
||||
pub fn enumerate(&mut self, parent: &mut PciBusManager) -> Result<(), Error> {
|
||||
for bus in self.bus_number_start..self.bus_number_end {
|
||||
self.enumerate_bus(parent, bus)?;
|
||||
@ -126,12 +153,14 @@ impl PciBusSegment {
|
||||
}
|
||||
|
||||
impl PciBusManager {
|
||||
pub const fn new() -> Self {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
segments: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Walks the bus device list and calls init/init_irq functions on any devices with associated
|
||||
/// drivers
|
||||
pub fn setup_bus_devices() -> Result<(), Error> {
|
||||
Self::walk_bus_devices(|device| {
|
||||
setup_bus_device(device)?;
|
||||
@ -139,6 +168,8 @@ impl PciBusManager {
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterates over the bus devices, calling the function on each of them until either an error
|
||||
/// or `Ok(false)` is returned
|
||||
pub fn walk_bus_devices<F: FnMut(&mut PciBusDevice) -> Result<bool, Error>>(
|
||||
mut f: F,
|
||||
) -> Result<(), Error> {
|
||||
@ -155,6 +186,7 @@ impl PciBusManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Enumerates a bus segment provided by ACPI MCFG table entry
|
||||
pub fn add_segment_from_mcfg(entry: &McfgEntry) -> Result<(), Error> {
|
||||
let mut bus_segment = PciBusSegment {
|
||||
segment_number: entry.pci_segment_group as u8,
|
||||
@ -180,6 +212,7 @@ impl fmt::Display for PciAddress {
|
||||
}
|
||||
|
||||
impl PciAddress {
|
||||
/// Constructs a [PciAddress] representing a bus
|
||||
pub const fn for_bus(segment: u8, bus: u8) -> Self {
|
||||
Self {
|
||||
segment,
|
||||
@ -189,6 +222,7 @@ impl PciAddress {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a [PciAddress] representing a device on a given bus
|
||||
pub const fn with_device(self, device: u8) -> Self {
|
||||
Self {
|
||||
device,
|
||||
@ -197,6 +231,7 @@ impl PciAddress {
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a [PciAddress] representing a function of a given bus device
|
||||
pub const fn with_function(self, function: u8) -> Self {
|
||||
Self { function, ..self }
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
//! PCI Express ECAM interface
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
device::bus::pci::{PciConfigSpace, PciDeviceInfo},
|
||||
mem::{device::DeviceMemory, ConvertAddress},
|
||||
};
|
||||
use crate::mem::{device::DeviceMemory, ConvertAddress};
|
||||
|
||||
use super::{PciAddress, PciConfigurationSpace};
|
||||
|
||||
/// PCI Express Enhanced Configuration Access Mechanism
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PciEcam {
|
||||
@ -35,6 +34,13 @@ impl PciConfigurationSpace for PciEcam {
|
||||
}
|
||||
|
||||
impl PciEcam {
|
||||
/// Maps the physical address of a ECAM space for kernel access.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `phys_addr` must be a valid ECAM address. The address must not alias any other mapped
|
||||
/// regions. The address must be aligned to a 4KiB boundary and be valid for accesses within a
|
||||
/// 4KiB-sized range.
|
||||
pub unsafe fn map(phys_addr: usize) -> Result<Self, Error> {
|
||||
// TODO check align
|
||||
let mapping = DeviceMemory::map("pcie-ecam", phys_addr, 0x1000)?;
|
||||
@ -42,14 +48,12 @@ impl PciEcam {
|
||||
Ok(PciEcam { mapping })
|
||||
}
|
||||
|
||||
pub unsafe fn from_raw_parts(
|
||||
segment_phys_addr: usize,
|
||||
bus_offset: u8,
|
||||
address: PciAddress,
|
||||
) -> Result<Self, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Checks if the ECAM contains a valid device configuration space, mapping and returning a
|
||||
/// [PciEcam] if it does.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// See [PciEcam::map].
|
||||
pub unsafe fn probe_raw_parts(
|
||||
segment_phys_addr: usize,
|
||||
bus_offset: u8,
|
||||
|
@ -3,83 +3,157 @@ use super::{PciAddress, PciBaseAddress, PciEcam};
|
||||
pub(super) mod ecam;
|
||||
|
||||
macro_rules! pci_config_field_getter {
|
||||
(u32, $name:ident, $offset:expr) => {
|
||||
fn $name(&self) -> u32 {
|
||||
self.read_u32($offset)
|
||||
}
|
||||
($self:ident, u32, $offset:expr) => {
|
||||
$self.read_u32($offset)
|
||||
};
|
||||
|
||||
(u16, $name:ident, $offset:expr) => {
|
||||
fn $name(&self) -> u16 {
|
||||
self.read_u16($offset)
|
||||
}
|
||||
($self:ident, u16, $offset:expr) => {
|
||||
$self.read_u16($offset)
|
||||
};
|
||||
|
||||
(u8, $name:ident, $offset:expr) => {
|
||||
fn $name(&self) -> u8 {
|
||||
self.read_u8($offset)
|
||||
}
|
||||
($self:ident, u8, $offset:expr) => {
|
||||
$self.read_u8($offset)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pci_config_field {
|
||||
($offset:expr => $ty:ident, $getter:ident $(, $setter:ident)?) => {
|
||||
pci_config_field_getter!($ty, $getter, $offset);
|
||||
(
|
||||
$offset:expr => $ty:ident,
|
||||
$(#[$getter_meta:meta])* $getter:ident
|
||||
$(, $(#[$setter_meta:meta])* $setter:ident)?
|
||||
) => {
|
||||
$(#[$getter_meta])*
|
||||
fn $getter(&self) -> $ty {
|
||||
pci_config_field_getter!(self, $ty, $offset)
|
||||
}
|
||||
|
||||
$(
|
||||
fn $setter(&self, value: $ty) {
|
||||
$(#[$setter_meta])*
|
||||
fn $setter(&self, _value: $ty) {
|
||||
todo!()
|
||||
}
|
||||
)?
|
||||
};
|
||||
}
|
||||
|
||||
/// Provides access to the legacy (port I/O-driven) PCI configuration space
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct PciLegacyConfigurationSpace {
|
||||
#[allow(unused)]
|
||||
address: PciAddress,
|
||||
}
|
||||
|
||||
/// Describes a configuration space access method for a PCI device
|
||||
#[derive(Debug)]
|
||||
pub enum PciConfigSpace {
|
||||
/// Legacy configuration space.
|
||||
///
|
||||
/// See [PciLegacyConfigurationSpace].
|
||||
Legacy(PciAddress),
|
||||
|
||||
/// Enhanced Configuration Access Mechanism (PCIe).
|
||||
///
|
||||
/// See [PciEcam].
|
||||
Ecam(PciEcam),
|
||||
}
|
||||
|
||||
/// Interface for accessing the configuration space of a device
|
||||
pub trait PciConfigurationSpace {
|
||||
/// Reads a 32-bit value from the device configuration space.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The `offset` must be u32-aligned.
|
||||
fn read_u32(&self, offset: usize) -> u32;
|
||||
|
||||
/// Reads a 16-bit value from the device configuration space.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The `offset` must be u16-aligned.
|
||||
fn read_u16(&self, offset: usize) -> u16 {
|
||||
assert_eq!(offset & 1, 0);
|
||||
let value = self.read_u32(offset & !3);
|
||||
(value >> ((offset & 3) * 8)) as u16
|
||||
}
|
||||
|
||||
/// Reads a byte from the device configuration space.
|
||||
fn read_u8(&self, offset: usize) -> u8 {
|
||||
let value = self.read_u32(offset & !3);
|
||||
(value >> ((offset & 3) * 8)) as u8
|
||||
}
|
||||
|
||||
/// Returns `true` if the device is present on the bus (i.e. configuration space is not filled
|
||||
/// with only 1's)
|
||||
fn is_valid(&self) -> bool {
|
||||
self.vendor_id() != 0xFFFF && self.device_id() != 0xFFFF
|
||||
}
|
||||
|
||||
pci_config_field!(0x00 => u16, vendor_id);
|
||||
pci_config_field!(0x02 => u16, device_id);
|
||||
pci_config_field!(0x04 => u16, command, set_command);
|
||||
pci_config_field!(0x06 => u16, status);
|
||||
pci_config_field!(
|
||||
0x00 => u16,
|
||||
#[doc = "Returns the Vendor ID"] vendor_id
|
||||
);
|
||||
pci_config_field!(0x02 => u16,
|
||||
#[doc = "Returns the Device ID"] device_id
|
||||
);
|
||||
pci_config_field!(
|
||||
0x04 => u16,
|
||||
#[doc = "Returns the value of the command register"] command,
|
||||
#[doc = "Writes to the command word register"] set_command
|
||||
);
|
||||
pci_config_field!(
|
||||
0x06 => u16,
|
||||
#[doc = "Returns the value of the status register"] status
|
||||
);
|
||||
|
||||
pci_config_field!(0x08 => u8, rev_id);
|
||||
pci_config_field!(0x09 => u8, prog_if);
|
||||
pci_config_field!(0x0A => u8, subclass);
|
||||
pci_config_field!(0x0B => u8, class_code);
|
||||
pci_config_field!(
|
||||
0x08 => u8,
|
||||
#[doc = "Returns the device Revision ID"]
|
||||
rev_id
|
||||
);
|
||||
pci_config_field!(
|
||||
0x09 => u8,
|
||||
#[doc = "Returns the device Prog IF field"]
|
||||
prog_if
|
||||
);
|
||||
pci_config_field!(
|
||||
0x0A => u8,
|
||||
#[doc = "Returns the device Subclass field"]
|
||||
subclass
|
||||
);
|
||||
pci_config_field!(
|
||||
0x0B => u8,
|
||||
#[doc = "Returns the device Class Code field"]
|
||||
class_code
|
||||
);
|
||||
|
||||
// ...
|
||||
pci_config_field!(0x0E => u8, header_type);
|
||||
// Header Type 1 only
|
||||
pci_config_field!(0x19 => u8, secondary_bus);
|
||||
pci_config_field!(
|
||||
0x0E => u8,
|
||||
#[doc = "Returns the header type of the device"]
|
||||
header_type
|
||||
);
|
||||
pci_config_field!(
|
||||
0x19 => u8,
|
||||
#[doc = r#"
|
||||
Returns the secondary bus number associated with this device
|
||||
|
||||
// Header Type 0 only
|
||||
# Note
|
||||
|
||||
The function is only valid for devices with `header_type() == 1`
|
||||
"#]
|
||||
secondary_bus
|
||||
);
|
||||
|
||||
/// Returns the value of the Base Address Register with given index.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The function is only valid for devices with `header_type() == 0`
|
||||
///
|
||||
/// The `index` corresponds to the actual configuration space BAR index, i.e. if a 64-bit
|
||||
/// address occupies [BAR0, BAR1] and BAR 1 is requested, the function will return [None].
|
||||
fn bar(&self, index: usize) -> Option<PciBaseAddress> {
|
||||
assert!(index < 6);
|
||||
|
||||
|
@ -513,6 +513,7 @@ pub fn add_console_autoflush(console: &'static dyn DisplayConsole) {
|
||||
CONSOLES.lock().push(console);
|
||||
}
|
||||
|
||||
/// Flushes console buffers to their displays
|
||||
pub fn flush_consoles() {
|
||||
for console in CONSOLES.lock().iter() {
|
||||
let mut state = console.state().lock();
|
||||
|
@ -8,6 +8,7 @@ use core::{
|
||||
use linked_list_allocator::Heap;
|
||||
use spinning_top::Spinlock;
|
||||
|
||||
/// Kernel heap manager
|
||||
pub struct KernelAllocator {
|
||||
inner: Spinlock<Heap>,
|
||||
}
|
||||
@ -46,6 +47,7 @@ unsafe impl GlobalAlloc for KernelAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
/// Kernel's global allocator
|
||||
#[global_allocator]
|
||||
pub static GLOBAL_HEAP: KernelAllocator = KernelAllocator::empty();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! Kernel panic handler code
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering};
|
||||
use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
|
||||
use device_api::interrupt::IpiDeliveryTarget;
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
//! Various kernel utility functions
|
||||
use core::time::Duration;
|
||||
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::arch::{Architecture, ARCHITECTURE};
|
||||
|
||||
/// Performs a busy-loop sleep until the specified duration has passed
|
||||
pub fn polling_sleep(duration: Duration) -> Result<(), Error> {
|
||||
let timer = ARCHITECTURE.monotonic_timer();
|
||||
let deadline = timer.monotonic_timestamp()? + duration;
|
||||
|
Loading…
x
Reference in New Issue
Block a user