refactor: fix kernel warnings

This commit is contained in:
Mark Poliakov 2023-09-05 16:13:15 +03:00
parent 309c5c3e9f
commit f88ca9b6d9
12 changed files with 203 additions and 52 deletions

View File

@ -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();

View File

@ -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},
};

View File

@ -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));

View File

@ -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::{

View File

@ -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];

View File

@ -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 }
}

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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;