dt: rework device-tree, proper interrupt handling

This commit is contained in:
Mark Poliakov 2024-12-16 00:23:23 +02:00
parent ccb5a6a7eb
commit a9340ea089
18 changed files with 838 additions and 591 deletions

View File

@ -45,31 +45,80 @@ impl<T> OneTimeInit<T> {
}
pub fn try_init_with_opt<F: FnOnce() -> Result<T, Error>>(&self, f: F) -> Result<&T, Error> {
if self
.state
.compare_exchange(
Self::STATE_UNINITIALIZED,
Self::STATE_INITIALIZING,
Ordering::Release,
Ordering::Relaxed,
)
.is_err()
{
if !self.try_begin_init() {
// Already initialized
return Err(Error::AlreadyExists);
}
let value = match f() {
Ok(val) => val,
Err(err) => {
self.state
.store(Self::STATE_UNINITIALIZED, Ordering::Release);
return Err(err);
match f() {
Ok(value) => {
let value = unsafe { (*self.value.get()).write(value) };
self.finish_init();
Ok(value)
}
};
Err(error) => {
self.fail_init();
Err(error)
}
}
}
let value = unsafe { (*self.value.get()).write(value) };
pub fn or_init_with<F: FnOnce() -> T>(&self, f: F) -> &T {
if !self.try_begin_init() {
return self.wait_for_init();
}
let value = unsafe { (*self.value.get()).write(f()) };
self.finish_init();
value
}
pub fn or_init_with_opt<F: FnOnce() -> Option<T>>(&self, f: F) -> Option<&T> {
if !self.try_begin_init() {
return Some(self.wait_for_init());
}
match f() {
Some(value) => {
let value = unsafe { (*self.value.get()).write(value) };
self.finish_init();
Some(value)
}
None => {
self.fail_init();
None
}
}
}
pub fn or_try_init_with<F: FnOnce() -> Result<T, Error>>(&self, f: F) -> Result<&T, Error> {
if !self.try_begin_init() {
return Ok(self.wait_for_init());
}
match f() {
Ok(value) => {
let value = unsafe { (*self.value.get()).write(value) };
self.finish_init();
Ok(value)
}
Err(error) => {
// Init failed
self.fail_init();
Err(error)
}
}
}
fn try_begin_init(&self) -> bool {
self.state
.compare_exchange(
Self::STATE_UNINITIALIZED,
Self::STATE_INITIALIZING,
Ordering::Acquire,
Ordering::Relaxed,
)
.is_ok()
}
fn finish_init(&self) {
self.state
.compare_exchange(
Self::STATE_INITIALIZING,
@ -78,44 +127,38 @@ impl<T> OneTimeInit<T> {
Ordering::Relaxed,
)
.unwrap();
Ok(value)
}
pub fn or_init_with<F: FnOnce() -> T>(&self, f: F) -> &T {
match self.try_init_with(f) {
Some(value) => value,
None => self.get(),
}
}
pub fn try_init_with<F: FnOnce() -> T>(&self, f: F) -> Option<&T> {
if self
.state
fn fail_init(&self) {
self.state
.compare_exchange(
Self::STATE_UNINITIALIZED,
Self::STATE_INITIALIZING,
Self::STATE_UNINITIALIZED,
Ordering::Release,
Ordering::Relaxed,
)
.is_err()
{
.unwrap();
}
fn wait_for_init(&self) -> &T {
while self.state.load(Ordering::Acquire) != Self::STATE_INITIALIZED {
core::hint::spin_loop();
}
unsafe { (*self.value.get()).assume_init_ref() }
}
pub fn try_init_with<F: FnOnce() -> T>(&self, f: F) -> Result<&T, Error> {
if !self.try_begin_init() {
// Already initialized
return None;
return Err(Error::AlreadyExists);
}
let value = unsafe { (*self.value.get()).write(f()) };
self.state
.compare_exchange(
Self::STATE_INITIALIZING,
Self::STATE_INITIALIZED,
Ordering::Release,
Ordering::Relaxed,
)
.unwrap();
self.finish_init();
Some(value)
Ok(value)
}
/// Sets the underlying value of the [OneTimeInit]. If already initialized, panics.

View File

@ -208,6 +208,7 @@ pub struct PciBusSegment {
devices: Vec<PciBusDevice>,
}
#[derive(Debug)]
pub enum PciRangeType {
Configuration,
Io,

View File

@ -1,9 +1,6 @@
//! Bus device interfaces
use core::ops::Range;
use alloc::sync::Arc;
use yggdrasil_abi::error::Error;
use crate::device::Device;
/// Bus device which provides an interconnect between two or more address spaces.
@ -13,7 +10,5 @@ pub trait Bus: Device {
/// Translates a range of bus addresses into the addresses represented in host memory.
///
/// NOTE: nested busses with bus1 -> bus0 -> host translation schemes are not yet supported.
fn map_range(&self, bus_range: Range<u64>) -> Result<Range<u64>, Error>;
fn enumerate(&self, handler: fn(Arc<dyn Device>));
fn map_range(&self, bus_range: Range<u64>) -> Option<Range<u64>>;
}

View File

@ -1,6 +1,8 @@
use alloc::sync::Arc;
use yggdrasil_abi::error::Error;
use crate::bus::Bus;
pub trait Device: Sync + Send {
fn display_name(&self) -> &str;
@ -36,4 +38,8 @@ pub trait Device: Sync + Send {
unsafe fn deinit(&self) -> Result<(), Error> {
Ok(())
}
fn as_bus(self: Arc<Self>) -> Option<Arc<dyn Bus>> {
None
}
}

View File

@ -3,6 +3,12 @@ use yggdrasil_abi::error::Error;
use crate::device::Device;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FullIrq {
pub irq: Irq,
pub options: IrqOptions,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Irq {
Private(u32),
@ -27,7 +33,7 @@ pub enum IrqTrigger {
Level,
}
#[derive(Default, Clone, Copy, Debug)]
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq)]
pub struct IrqOptions {
pub level: IrqLevel,
pub trigger: IrqTrigger,

View File

@ -2,258 +2,455 @@
use core::ops::Range;
use alloc::{sync::Arc, vec::Vec};
use device_api::{bus::Bus, device::Device};
use discrete_range_map::{DiscreteRangeMap, InclusiveInterval};
use alloc::{
collections::btree_map::BTreeMap,
sync::{Arc, Weak},
vec::Vec,
};
use device_api::{bus::Bus, device::Device, interrupt::FullIrq};
use fdt_rs::{prelude::PropReader, spec::Phandle};
use libk_mm::address::PhysicalAddress;
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use yggdrasil_abi::error::Error;
use crate::dt::{
DevTreeIndexNodeExt, DevTreeIndexNodePropGet, DevTreeIndexPropExt, DeviceTree, TNode, TProp,
};
use crate::dt::{DevTreeIndexNodePropGet, DevTreeIndexPropExt, DeviceTree, TNode, TProp};
pub macro device_tree_driver(
compatible: [$($compatible:expr),+ $(,)?],
probe($node:ident) => $probe_body:block
compatible: [$($compatible:literal),+ $(,)?],
driver: $driver:tt
) {
#[used]
struct __DtDriver;
impl $crate::driver::Driver for __DtDriver $driver
static __DT_DRIVER: __DtDriver = __DtDriver;
#[link_section = ".init_array"]
static __FN_POINTER: extern "C" fn() = __register_fn;
#[used]
static __REGISTER_FN: extern "C" fn() = __register_fn;
fn __probe_fn($node: &$crate::driver::Node) -> Option<alloc::sync::Arc<dyn device_api::device::Device>>
$probe_body
#[inline(never)]
extern "C" fn __register_fn() {
$crate::driver::register_driver($crate::driver::Driver {
compatible: &[$($compatible),+],
probe_fn: __probe_fn
});
$crate::driver::register_driver(
&[$($compatible),+],
&__DT_DRIVER
)
}
}
pub struct Driver {
pub compatible: &'static [&'static str],
pub probe_fn: fn(&Node) -> Option<Arc<dyn Device>>,
pub trait Driver: Sync {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>>;
fn enumerate_children(&self, node: &Arc<Node>) {
let _ = node;
}
}
pub struct DriverRegistration {
pub compatible: &'static [&'static str],
pub imp: &'static dyn Driver,
}
#[derive(Clone)]
pub struct Node {
// Info from device tree
dt_node: TNode<'static>,
bus_address_cells: usize,
bus_size_cells: usize,
interrupt_parent: Option<Phandle>,
name: Option<&'static str>,
compatible: Option<&'static str>,
node: TNode<'static>,
// Hierachy info
children: OneTimeInit<Vec<Arc<Node>>>,
parent: Option<Weak<Node>>,
// Driver/device info
device: OneTimeInit<NodeDevice>,
init_token: OneTimeInit<()>,
interrupt_controller: OneTimeInit<Arc<dyn DeviceTreeInterruptController>>,
}
struct NodeDevice {
driver: &'static dyn Driver,
device: Arc<dyn Device>,
}
struct EnumerationContext {
address_cells: usize,
size_cells: usize,
interrupt_parent: Option<Phandle>,
}
pub struct ProbeContext {
bus: Option<Weak<dyn Bus>>,
}
pub trait DeviceTreeInterruptController {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq>;
}
impl Node {
pub fn probe(&self) -> Option<Arc<dyn Device>> {
// Then probe the node itself
let compatible = self.compatible?;
let drivers = DRIVERS.read();
for driver in drivers.iter() {
if driver.compatible.contains(&compatible)
&& let Some(device) = (driver.probe_fn)(self)
{
return Some(device);
}
fn probe_upwards(self: Arc<Self>) -> (Option<Arc<dyn Device>>, Option<Weak<dyn Bus>>) {
let mut parent_bus = None;
if let Some(parent) = self.parent.as_ref().and_then(Weak::upgrade) {
let (_, bus) = parent.probe_upwards();
parent_bus = bus;
}
None
}
pub fn probe_recursive(&self) -> Option<Arc<dyn Device>> {
// Make sure all parents are probed first
if let Some(parent) = self.node.parent() {
let node = from_dt_node(parent);
node.probe_recursive()
} else {
None
let cx = ProbeContext {
bus: parent_bus.clone(),
};
self.probe()
let inner = self.device.or_init_with_opt(|| {
let compatible = self.compatible?;
let drivers = DRIVERS.read();
let driver = drivers.iter().find(|d| d.matches(compatible))?;
let device = driver.imp.probe(&self, &cx)?;
Some(NodeDevice {
driver: driver.imp,
device,
})
});
let device = inner.map(|d| d.device.clone());
let bus = if let Some(device) = device.as_ref() {
device.clone().as_bus().as_ref().map(Arc::downgrade)
} else {
parent_bus
};
(device, bus)
}
pub fn probe(self: Arc<Self>) -> Option<Arc<dyn Device>> {
let (device, _) = self.probe_upwards();
device
}
pub fn make_interrupt_controller(&self, intc: Arc<dyn DeviceTreeInterruptController>) {
self.interrupt_controller.init(intc);
}
pub fn driver(&self) -> Option<&'static dyn Driver> {
Some(self.device.try_get()?.driver)
}
pub fn lazy_init(self: Arc<Self>) -> Option<Result<(), Error>> {
let device = self.clone().probe()?;
let result = self.init_token.or_try_init_with(|| {
unsafe { device.init() }?;
Ok(())
});
match result {
Ok(()) => Some(Ok(())),
Err(error) => Some(Err(error)),
}
}
pub fn init_irqs(self: Arc<Self>) -> Option<Result<(), Error>> {
match self.clone().lazy_init() {
Some(Ok(())) => {
let device = self.device.get();
let status = unsafe { device.device.clone().init_irq() };
Some(status)
}
Some(Err(_)) | None => None,
}
}
pub fn force_init(self: Arc<Self>) -> Result<(), Error> {
let device = self.clone().probe().ok_or(Error::DoesNotExist)?;
self.init_token.try_init_with_opt(|| {
unsafe { device.init() }?;
Ok(())
})?;
Ok(())
}
pub fn children(&self) -> impl Iterator<Item = &Arc<Node>> {
self.children.get().iter()
}
// Properties
pub fn name(&self) -> Option<&'static str> {
self.name
}
pub fn bus_range(&self, index: usize) -> Option<Range<u64>> {
let reg = self.property("reg")?;
let address_cells = self.parent_address_cells();
let size_cells = self.parent_size_cells();
let (base, len) = reg.read_cells(index, (address_cells, size_cells))?;
Some(base..base + len)
let reg = crate::find_prop(&self.dt_node, "reg")?;
let (base, size) = reg.read_cells(index, (self.bus_address_cells, self.bus_size_cells))?;
Some(base..base + size)
}
pub fn mapped_range(&self, index: usize) -> Option<Range<u64>> {
pub fn map_range(&self, context: &ProbeContext, index: usize) -> Option<Range<u64>> {
let bus_range = self.bus_range(index)?;
if self.is_parent_root() {
return Some(bus_range);
}
map_bus_range(bus_range)
context.map_range(bus_range)
}
pub fn parent_address_cells(&self) -> usize {
self.node.address_cells()
pub fn map_base(&self, context: &ProbeContext, index: usize) -> Option<PhysicalAddress> {
self.map_range(context, index)
.map(|range| PhysicalAddress::from_u64(range.start))
}
pub fn parent_size_cells(&self) -> usize {
self.node.size_cells()
pub fn interrupt(&self, index: usize) -> Option<FullIrq> {
let interrupts = self.property("interrupts")?;
let phandle = self.interrupt_parent?;
map_interrupt(phandle, &interrupts, index)
}
pub fn interrupt_from(&self, property: &TProp, index: usize) -> Option<FullIrq> {
let phandle = self.interrupt_parent?;
map_interrupt(phandle, property, index)
}
pub fn interrupt_controller(&self) -> Option<Arc<Node>> {
INTERRUPT_CONTROLLERS
.read()
.get(&self.interrupt_parent?)
.cloned()
}
pub fn bus_address_cells(&self) -> usize {
self.bus_address_cells
}
pub fn self_interrupt_cells(&self) -> Option<usize> {
self.prop::<u32>("#interrupt-cells").map(|v| v as usize)
}
pub fn self_address_cells(&self) -> Option<usize> {
self.property_val::<u32>("#address-cells")
.map(|val| val as usize)
self.prop::<u32>("#address-cells").map(|v| v as usize)
}
pub fn self_size_cells(&self) -> Option<usize> {
self.property_val::<u32>("#size-cells")
.map(|val| val as usize)
self.prop::<u32>("#size-cells").map(|v| v as usize)
}
pub fn property(&self, name: &str) -> Option<TProp<'static>> {
crate::find_prop(&self.node, name)
crate::find_prop(&self.dt_node, name)
}
pub fn property_val<T>(&self, name: &str) -> Option<T>
pub fn prop<T>(&self, name: &str) -> Option<T>
where
TNode<'static>: DevTreeIndexNodePropGet<T>,
{
self.node.prop(name)
self.dt_node.prop(name)
}
}
pub fn name(&self) -> &str {
self.node.name().unwrap_or("<unknown>")
}
pub fn children(&self) -> impl Iterator<Item = Node> {
self.node.children().map(from_dt_node)
}
fn is_parent_root(&self) -> bool {
let Some(parent) = self.node.parent() else {
return true;
};
parent.parent().is_none()
impl ProbeContext {
pub fn map_range(&self, range: Range<u64>) -> Option<Range<u64>> {
if let Some(bus) = self.bus.as_ref().and_then(Weak::upgrade) {
// Use parent bus to map the address
bus.map_range(range)
} else {
// Identity
Some(range)
}
}
}
unsafe impl Sync for Node {}
unsafe impl Send for Node {}
static DRIVERS: IrqSafeRwLock<Vec<Driver>> = IrqSafeRwLock::new(Vec::new());
static BUS_RANGES: OneTimeInit<
IrqSafeRwLock<DiscreteRangeMap<u64, InclusiveInterval<u64>, Arc<dyn Bus>>>,
> = OneTimeInit::new();
static BUSSES: IrqSafeRwLock<Vec<Arc<dyn Bus>>> = IrqSafeRwLock::new(Vec::new());
static DRIVERS: IrqSafeRwLock<Vec<DriverRegistration>> = IrqSafeRwLock::new(Vec::new());
static ROOT: OneTimeInit<Arc<Node>> = OneTimeInit::new();
static DEVICE_TREE: OneTimeInit<&'static DeviceTree> = OneTimeInit::new();
static INTERRUPT_CONTROLLERS: IrqSafeRwLock<BTreeMap<Phandle, Arc<Node>>> =
IrqSafeRwLock::new(BTreeMap::new());
pub fn register_driver(driver: Driver) {
DRIVERS.write().push(driver);
}
fn unflatten_node(
dt: TNode<'static>,
parent: Option<Weak<Node>>,
ctx: &EnumerationContext,
) -> Arc<Node> {
let name = dt.name().ok();
// TODO <stringlist>
let compatible: Option<&str> = dt.prop("compatible");
pub fn register_bus<I: IntoIterator<Item = Range<u64>>>(bus: Arc<dyn Bus>, ranges: I) {
let bus_ranges = BUS_RANGES.or_init_with(|| IrqSafeRwLock::new(DiscreteRangeMap::new()));
let mut bus_ranges = bus_ranges.write();
// Extract #...-cells for children
let address_cells: Option<u32> = dt.prop("#address-cells");
let size_cells: Option<u32> = dt.prop("#size-cells");
let address_cells = address_cells
.map(|s| s as usize)
.unwrap_or(ctx.address_cells);
let size_cells = size_cells.map(|s| s as usize).unwrap_or(ctx.size_cells);
// Extract interrupt-parent for children
let interrupt_parent: Option<Phandle> = dt.prop("interrupt-parent");
let interrupt_parent = interrupt_parent.or(ctx.interrupt_parent);
for range in ranges {
let range = InclusiveInterval::from(range.start..range.end);
bus_ranges.insert_strict(range, bus.clone()).ok();
let is_interrupt_controller = dt.props().any(|p| {
p.name()
.map(|name| name == "interrupt-controller")
.unwrap_or(false)
});
let phandle = dt.prop("phandle");
// Setup this node
let node = Arc::new(Node {
dt_node: dt.clone(),
interrupt_parent,
bus_address_cells: ctx.address_cells,
bus_size_cells: ctx.size_cells,
name,
compatible,
children: OneTimeInit::new(),
parent,
device: OneTimeInit::new(),
init_token: OneTimeInit::new(),
interrupt_controller: OneTimeInit::new(),
});
if let Some(phandle) = phandle
&& is_interrupt_controller
{
INTERRUPT_CONTROLLERS.write().insert(phandle, node.clone());
}
BUSSES.write().push(bus);
// Unflatten children
let mut children = Vec::new();
let child_ctx = EnumerationContext {
address_cells,
size_cells,
interrupt_parent,
};
for child in dt.children() {
let child_node = unflatten_node(child, Some(Arc::downgrade(&node)), &child_ctx);
children.push(child_node);
}
node.children.init(children);
node
}
pub fn enumerate_busses(dt: &'static DeviceTree, handler: fn(Arc<dyn Device>)) {
// Enumerate root first
for node in dt.root().children() {
let node = from_dt_node(node);
pub fn unflatten_device_tree(dt: &'static DeviceTree) {
const DEFAULT_ADDRESS_CELLS: u32 = 2;
const DEFAULT_SIZE_CELLS: u32 = 1;
if let Some(device) = node.probe() {
handler(device);
DEVICE_TREE.init(dt);
let ctx = EnumerationContext {
address_cells: DEFAULT_ADDRESS_CELLS as usize,
size_cells: DEFAULT_SIZE_CELLS as usize,
interrupt_parent: None,
};
let root = unflatten_node(dt.root(), None, &ctx);
ROOT.init(root);
}
pub fn interrupt_controller(phandle: Phandle) -> Option<Arc<Node>> {
let interrupt_controller = INTERRUPT_CONTROLLERS.read().get(&phandle).cloned()?;
interrupt_controller.clone().probe()?;
Some(interrupt_controller)
}
pub fn map_interrupt_at(
interrupt_controller: &Arc<Node>,
property: &TProp,
offset: usize,
) -> Option<FullIrq> {
let interrupt_controller = interrupt_controller.interrupt_controller.try_get()?;
interrupt_controller.map_interrupt(property, offset)
}
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<FullIrq> {
let interrupt_controller = interrupt_controller(phandle)?;
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
map_interrupt_at(&interrupt_controller, property, index * interrupt_cells)
}
fn walk_node<T, V: FnMut(&Arc<Node>) -> Option<T>>(node: &Arc<Node>, visitor: &mut V) -> Option<T> {
if let Some(value) = visitor(node) {
return Some(value);
}
for child in node.children.get() {
if let Some(value) = walk_node(child, visitor) {
return Some(value);
}
}
let busses = BUSSES.read();
for bus in busses.iter() {
bus.enumerate(handler);
None
}
pub fn walk_device_tree<T, V: FnMut(&Arc<Node>) -> Option<T>>(mut visitor: V) -> Option<T> {
if let Some(root) = ROOT.try_get() {
walk_node(root, &mut visitor)
} else {
None
}
}
pub fn map_bus_range(bus_range: Range<u64>) -> Option<Range<u64>> {
let bus_ranges = BUS_RANGES.try_get()?;
let bus_ranges = bus_ranges.read();
pub fn find_node(name: &str) -> Option<Arc<Node>> {
let dt = *DEVICE_TREE.try_get()?;
let mut path = dt.resolve_alias(name)?.trim_matches('/');
let mut current = ROOT.try_get()?.clone();
let query = InclusiveInterval::from(bus_range.start..bus_range.end);
let mut iter = bus_ranges.overlapping(query);
let (_, bus) = iter.next()?;
if iter.next().is_some() {
// Cannot cross multiple bus segments with one range
return None;
loop {
if path.is_empty() {
return Some(current);
}
let (left, rest) = match path.split_once('/') {
Some(elem) => elem,
None => (path, ""),
};
path = rest.trim_start_matches('/');
let child = current
.children()
.find(|node| node.name.map(|name| name == left).unwrap_or(false))?;
current = child.clone();
}
bus.map_range(bus_range).ok()
}
fn from_dt_node(node: TNode<'static>) -> Node {
// TODO support "compatible" as a <stringlist>
let compatible = node.prop("compatible");
Node { compatible, node }
pub fn lazy_init<S: Fn(&Arc<Node>), F: Fn(&Arc<Node>, Error)>(
success_handler: S,
error_handler: F,
) {
walk_device_tree::<(), _>(|node| {
match node.clone().lazy_init() {
Some(Ok(())) => success_handler(node),
Some(Err(error)) => error_handler(node, error),
None => (),
}
None
});
}
pub fn dt_path(dt: &'static DeviceTree, path: &str) -> Result<Node, Error> {
let path = dt.resolve_alias(path).ok_or(Error::DoesNotExist)?;
let node = dt.find_absolute(path).ok_or(Error::DoesNotExist)?;
Ok(from_dt_node(node))
pub fn init_irqs<S: Fn(&Arc<Node>), F: Fn(&Arc<Node>, Error)>(
success_handler: S,
error_handler: F,
) {
walk_device_tree::<(), _>(|node| {
match node.clone().init_irqs() {
Some(Ok(())) => success_handler(node),
Some(Err(error)) => error_handler(node, error),
None => (),
}
None
});
}
// /// "Probes" a device tree node for any matching device, registering it if a compatible driver is
// /// found
// pub fn probe_dt_node(dt: &DevTreeNodeInfo) -> Option<Arc<dyn Device>> {
// // TODO use list, not just the first item
// let compatible = dt.node.prop("compatible")?;
// let probe = dt_match_compatible(compatible)?;
// let device = (probe.probe_func)(dt)?;
// Some(device)
// }
//
// /// Performs a walk of a device tree, visiting all nodes which are parts of the given path
// pub fn traverse_dt_path<'a, F: FnMut(&str, DevTreeNodeInfo) -> Result<(), Error>>(
// root: &TNode,
// mut f: F,
// ) -> Result<(), Error> {
// loop {}
// }
//
// /// Performs shallow walk of a device tree node and executes the visitor function on each node
// pub fn enumerate_dt<
// 'a,
// I: Iterator<Item = DevTreeIndexNode<'a, 'a, 'a>>,
// F: FnMut(&str, DevTreeNodeInfo) -> Result<(), Error>,
// >(
// address_cells: usize,
// size_cells: usize,
// nodes: I,
// mut f: F,
// ) -> Result<(), usize> {
// let mut failed_count = 0;
//
// for node in nodes {
// // Skip /cpus and /memory*
// let probe = DevTreeNodeInfo {
// address_cells,
// size_cells,
// node,
// };
//
// let Ok(name) = probe.node.name() else {
// continue;
// };
// let Some(compatible) = probe.node.prop("compatible") else {
// continue;
// };
//
// if let Err(error) = f(compatible, probe) {
// log::warn!("{}: {:?}", name, error);
// failed_count += 1;
// }
// }
//
// if failed_count == 0 {
// Ok(())
// } else {
// Err(failed_count)
// }
// }
impl DriverRegistration {
fn matches(&self, compatible: &str) -> bool {
self.compatible.contains(&compatible)
}
}
pub fn register_driver(compatible: &'static [&'static str], driver: &'static dyn Driver) {
DRIVERS.write().push(DriverRegistration {
compatible,
imp: driver,
});
}

View File

@ -79,6 +79,26 @@ impl CellTuple for (u64, u64, u64) {
}
}
impl CellTuple for (u64, u64, u64, u64) {
type Sizes = (usize, usize, usize, usize);
fn read<P: DevTreeIndexPropExt + ?Sized>(
property: &P,
offset: usize,
sizes: Self::Sizes,
) -> Option<Self> {
let v0 = property.read_cell(offset, sizes.0)?;
let v1 = property.read_cell(offset + sizes.0, sizes.1)?;
let v2 = property.read_cell(offset + sizes.0 + sizes.1, sizes.2)?;
let v3 = property.read_cell(offset + sizes.0 + sizes.1 + sizes.2, sizes.3)?;
Some((v0, v1, v2, v3))
}
fn entry_size(sizes: Self::Sizes) -> usize {
sizes.0 + sizes.1 + sizes.2 + sizes.3
}
}
/// Helper trait to provide extra functionality for [DevTreeIndexProp]
#[allow(clippy::len_without_is_empty)]
pub trait DevTreeIndexPropExt {
@ -95,6 +115,10 @@ pub trait DevTreeIndexPropExt {
T::read(self, offset, sizes)
}
fn read_cells_at<T: CellTuple>(&self, offset: usize, sizes: T::Sizes) -> Option<T> {
T::read(self, offset, sizes)
}
fn iter_cells<T: CellTuple>(&self, sizes: T::Sizes) -> CellTupleIterator<Self, T> {
CellTupleIterator {
property: self,

View File

@ -25,6 +25,7 @@ const MAX_DEBUG_SINKS: usize = 4;
const RING_LOGGER_CAPACITY: usize = 65536;
static RING_AVAILABLE: AtomicBool = AtomicBool::new(false);
static SERIAL_SINK_SET_UP: AtomicBool = AtomicBool::new(false);
struct KernelLoggerSink;
/// Locking log sink for dumping panic info
@ -317,6 +318,14 @@ pub fn add_sink(sink: Arc<dyn DebugSink>, level: LogLevel) {
DEBUG_SINKS.write().push(DebugSinkWrapper::Arc(level, sink));
}
pub fn add_serial_sink(sink: Arc<dyn DebugSink>, level: LogLevel) {
if SERIAL_SINK_SET_UP.swap(true, Ordering::Acquire) {
return;
}
add_sink(sink, level);
}
/// Print a trace message coming from a process
pub fn program_trace(process: &Process, thread: &Thread, message: &str) {
log::debug!(

View File

@ -97,7 +97,7 @@ impl SerialTerminalRegistry {
let id = self.registry.register(terminal.clone())?;
devfs::add_named_char_device(terminal, format!("ttyS{id}")).ok();
if let Some((sink, sink_level)) = sink_level {
debug::add_sink(sink, sink_level);
debug::add_serial_sink(sink, sink_level);
}
Ok(id)
}

View File

@ -8,12 +8,15 @@ use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable,
IpiDeliveryTarget, IpiMessage, Irq, IrqOptions, LocalInterruptController,
MessageInterruptController, MsiInfo,
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
LocalInterruptController, MessageInterruptController, MsiInfo,
},
};
use device_tree::driver::device_tree_driver;
use device_tree::{
driver::{device_tree_driver, DeviceTreeInterruptController, Node, ProbeContext},
dt::{DevTreeIndexPropExt, TProp},
};
use kernel_arch_aarch64::{GicInterface, CPU_COUNT};
use libk::{arch::Cpu, device::register_external_interrupt_controller, task::cpu_index};
use libk_mm::{
@ -199,6 +202,40 @@ impl LocalInterruptController for Gic {
}
}
impl DeviceTreeInterruptController for Gic {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
// IRQ_TYPE_NONE - 0
// IRQ_TYPE_EDGE_RISING - 1
// IRQ_TYPE_EDGE_FALLING - 2
// IRQ_TYPE_EDGE_BOTH - 3
// IRQ_TYPE_LEVEL_HIGH - 4
// IRQ_TYPE_LEVEL_LOW - 8
let sizes = (1, 1, 1);
let (kind, number, options) = property.read_cells_at(offset, sizes)?;
let number = number as u32;
let (trigger, level) = match options & 0xF {
0x01 => (IrqTrigger::Edge, IrqLevel::ActiveHigh),
0x02 => (IrqTrigger::Edge, IrqLevel::ActiveLow),
0x03 => return None, // TODO
0x04 => (IrqTrigger::Level, IrqLevel::ActiveHigh),
0x08 => (IrqTrigger::Level, IrqLevel::ActiveLow),
_ => return None,
};
let irq = match kind {
0x00 => Irq::External(number),
0x01 => Irq::Private(number),
_ => return None,
};
Some(FullIrq {
irq,
options: IrqOptions { trigger, level },
})
}
}
impl Gic {
/// Constructs an instance of GICv2.
///
@ -225,13 +262,20 @@ impl GicPerCpu {
device_tree_driver! {
compatible: ["arm,cortex-a15-gic", "arm,gic-400"],
probe(of) => {
let gicd_range = of.mapped_range(0)?;
let gicc_range = of.mapped_range(1)?;
driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
let gicd_range = node.map_range(context, 0)?;
let gicc_range = node.map_range(context, 1)?;
let gicd_base = PhysicalAddress::from_u64(gicd_range.start);
let gicc_base = PhysicalAddress::from_u64(gicc_range.start);
let gicd_base = PhysicalAddress::from_u64(gicd_range.start);
let gicc_base = PhysicalAddress::from_u64(gicc_range.start);
Some(Arc::new(unsafe { Gic::new(gicd_base, gicc_base) }))
let gic = Arc::new(unsafe { Gic::new(gicd_base, gicc_base) });
// Register device-tree interrupt controller
node.make_interrupt_controller(gic.clone());
Some(gic)
}
}
}

View File

@ -9,7 +9,10 @@ use device_api::{
interrupt::{Irq, LocalInterruptController},
ResetDevice,
};
use device_tree::dt::{DevTreeIndexNodePropGet, DeviceTree, FdtMemoryRegionIter};
use device_tree::{
driver::unflatten_device_tree,
dt::{DevTreeIndexNodePropGet, DeviceTree, FdtMemoryRegionIter},
};
use kernel_arch::Architecture;
use kernel_arch_aarch64::{
mem::{
@ -19,11 +22,7 @@ use kernel_arch_aarch64::{
},
ArchitectureImpl, PerCpuData,
};
use libk::{
arch::Cpu,
debug,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
};
use libk::{arch::Cpu, debug, device::external_interrupt_controller};
use libk_mm::{
address::PhysicalAddress,
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
@ -207,21 +206,19 @@ impl AArch64 {
}
#[inline(never)]
unsafe fn setup_serial_output(&self, dt: &'static DeviceTree) -> Result<bool, Error> {
unsafe fn setup_chosen_stdout(dt: &'static DeviceTree) -> Result<(), Error> {
// Get /chosen.stdout-path to get early debug printing
// TODO honor defined configuration value
let stdout = dt.chosen_stdout();
let stdout_path = stdout.map(|(p, _)| p);
let node = stdout_path.and_then(device_tree::driver::find_node);
if let Some(path) = stdout_path {
let node = device_tree::driver::dt_path(dt, path)?;
let device = node.probe_recursive().ok_or(Error::DoesNotExist)?;
device.clone().init()?;
DEVICE_REGISTRY.add_pending_initialization(device, true);
Ok(true)
} else {
Ok(false)
if let Some(node) = node {
node.force_init()?;
}
// No stdout
Ok(())
}
fn machine_name(dt: &'static DeviceTree) -> (Option<&'static str>, Option<&'static str>) {
@ -247,36 +244,38 @@ impl AArch64 {
Cpu::init_local(None, per_cpu);
if is_bsp {
// Will register drivers
call_init_array();
atomic::compiler_fence(Ordering::SeqCst);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI GPU Device",
0x1AF4,
0x1050,
ygg_driver_virtio_gpu::probe,
);
ygg_driver_pci::register_vendor_driver(
"Virtio PCI Network Device",
0x1AF4,
0x1000,
ygg_driver_virtio_net::probe,
);
ygg_driver_pci::register_class_driver(
"AHCI SATA Controller",
0x01,
Some(0x06),
Some(0x01),
ygg_driver_ahci::probe,
);
ygg_driver_pci::register_class_driver(
"USB xHCI",
0x0C,
Some(0x03),
Some(0x30),
ygg_driver_usb_xhci::probe,
);
// TODO
// ygg_driver_pci::register_vendor_driver(
// "Virtio PCI GPU Device",
// 0x1AF4,
// 0x1050,
// ygg_driver_virtio_gpu::probe,
// );
// ygg_driver_pci::register_vendor_driver(
// "Virtio PCI Network Device",
// 0x1AF4,
// 0x1000,
// ygg_driver_virtio_net::probe,
// );
// ygg_driver_pci::register_class_driver(
// "AHCI SATA Controller",
// 0x01,
// Some(0x06),
// Some(0x01),
// ygg_driver_ahci::probe,
// );
// ygg_driver_pci::register_class_driver(
// "USB xHCI",
// 0x0C,
// Some(0x03),
// Some(0x30),
// ygg_driver_usb_xhci::probe,
// );
debug::init();
@ -288,7 +287,9 @@ impl AArch64 {
Self::apply_machine_workarounds(compatible);
}
self.setup_serial_output(dt)?;
unflatten_device_tree(dt);
Self::setup_chosen_stdout(dt).ok();
if let Some(machine) = machine_name {
log::info!("Running on {machine:?}");
@ -297,12 +298,21 @@ impl AArch64 {
log::info!("Initializing aarch64 platform");
device_tree::driver::enumerate_busses(dt, |device| {
log::debug!("* {:?}", device.display_name());
DEVICE_REGISTRY.add_pending_initialization(device, false);
});
DEVICE_REGISTRY.run_initialization();
device_tree::driver::lazy_init(
|_| (),
|node, error| {
log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>"));
},
);
device_tree::driver::init_irqs(
|_| (),
|node, error| {
log::error!(
"{}: irq init error: {error:?}",
node.name().unwrap_or("<unknown>")
);
},
);
PciBusManager::setup_bus_devices()?;
} else {

View File

@ -7,16 +7,16 @@ use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq, IrqLevel, IrqOptions, IrqTrigger},
interrupt::{FullIrq, InterruptHandler},
};
use device_tree::driver::device_tree_driver;
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use kernel_arch::task::Scheduler;
use libk::{arch::Cpu, device::external_interrupt_controller, task::runtime, time};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
/// ARM Generic Timer driver
pub struct ArmTimer {
irq: Irq,
irq: FullIrq,
}
/// ARM timer tick interval (in some time units?)
@ -65,19 +65,12 @@ impl Device for ArmTimer {
let intc = external_interrupt_controller()?;
intc.register_irq(
self.irq,
IrqOptions {
level: IrqLevel::ActiveLow,
trigger: IrqTrigger::Level,
},
self.clone(),
)?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
CNTP_CTL_EL0.modify(CNTP_CTL_EL0::IMASK::CLEAR);
CNTP_TVAL_EL0.set(TICK_INTERVAL);
intc.enable_irq(self.irq)?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
@ -89,7 +82,7 @@ impl ArmTimer {
/// # Safety
///
/// The caller must ensure the function has not been called before.
pub const unsafe fn new(irq: Irq) -> Self {
pub const unsafe fn new(irq: FullIrq) -> Self {
Self { irq }
}
}
@ -97,12 +90,10 @@ impl ArmTimer {
// TODO handle interrupt-parent
device_tree_driver! {
compatible: ["arm,armv8-timer"],
probe(_dt) => {
// let interrupts = dt::find_prop(&dt.node, "interrupts")?;
// let irq_no = interrupts.read_cell(1, 1)? as u32;
// let irq = Irq::Private(irq_no);
let irq = Irq::Private(14);
Some(Arc::new(unsafe { ArmTimer::new(irq) }))
driver: {
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> {
let irq = node.interrupt(1)?;
Some(Arc::new(unsafe { ArmTimer::new(irq) }))
}
}
}

View File

@ -1,10 +1,10 @@
//! PCI bus device wrapper for device tree
use alloc::{collections::BTreeMap, vec::Vec};
use device_api::interrupt::{IrqLevel, IrqOptions, IrqTrigger};
use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec};
use device_api::{device::Device, interrupt::Irq};
use device_tree::{
device_tree_driver,
dt::{self, DevTreeIndexNodeExt, DevTreeIndexPropExt},
driver::{device_tree_driver, interrupt_controller, map_interrupt_at, Node, ProbeContext},
dt::DevTreeIndexPropExt,
};
use libk_mm::address::PhysicalAddress;
use ygg_driver_pci::{
@ -12,178 +12,139 @@ use ygg_driver_pci::{
PciAddress, PciAddressRange, PciBusManager, PciRangeType,
};
// fn extract_ranges(dt: &DevTreeNodeInfo) -> Vec<PciAddressRange> {
// let Some(ranges) = dt::find_prop(&dt.node, "ranges") else {
// return Vec::new();
// };
// let pci_address_cells = dt.node.address_cells();
// let pci_size_cells = dt.node.size_cells();
//
// let cells_per_range = dt.address_cells + pci_address_cells + pci_size_cells;
//
// assert_eq!(ranges.len() % cells_per_range, 0);
//
// let range_count = ranges.len() / (cells_per_range * 4);
//
// let mut result = Vec::new();
//
// for i in 0..range_count {
// let ty_bits = ranges.cell1_array_item(i * cells_per_range, 1).unwrap();
// let ty = match (ty_bits >> 24) & 0x3 {
// 0 => PciRangeType::Configuration,
// 1 => PciRangeType::Io,
// 2 => PciRangeType::Memory32,
// 3 => PciRangeType::Memory64,
// _ => unreachable!(),
// };
// let bus_number = (ty_bits >> 16) as u8;
//
// let pci_base = match pci_address_cells {
// 3 => {
// let hi = ranges.cell1_array_item(i * cells_per_range + 1, 1).unwrap();
// let lo = ranges.cell1_array_item(i * cells_per_range + 2, 1).unwrap();
//
// (hi << 32) | lo
// }
// _ => unimplemented!(),
// };
//
// let host_base = PhysicalAddress::from_u64(match dt.address_cells {
// 2 => {
// let hi = ranges
// .cell1_array_item(i * cells_per_range + pci_address_cells, 1)
// .unwrap();
// let lo = ranges
// .cell1_array_item(i * cells_per_range + pci_address_cells + 1, 1)
// .unwrap();
//
// (hi << 32) | lo
// }
// _ => unimplemented!(),
// });
//
// let size = match pci_size_cells {
// 2 => {
// let hi = ranges
// .cell1_array_item(
// i * cells_per_range + pci_address_cells + dt.address_cells,
// 1,
// )
// .unwrap();
// let lo = ranges
// .cell1_array_item(
// i * cells_per_range + pci_address_cells + dt.address_cells + 1,
// 1,
// )
// .unwrap();
//
// (hi << 32) | lo
// }
// _ => unimplemented!(),
// } as usize;
//
// result.push(PciAddressRange {
// ty,
// bus_number,
// host_base,
// pci_base,
// size,
// });
// }
//
// result
// }
//
// fn extract_interrupt_map(dt: &DevTreeNodeInfo) -> BTreeMap<PciInterrupt, PciInterruptRoute> {
// // let interrupt_map_mask = devtree::find_prop(&dt.node, "interrupt-map").unwrap();
// let interrupt_map = dt::find_prop(&dt.node, "interrupt-map").unwrap();
// let pci_address_cells = dt.node.address_cells();
//
// // TODO replace 3 with interrupt-cells in interrupt-controller
// let cells_per_imap = pci_address_cells + /* Pin */ 1 + /* #interrupt-cells in interrupt-controller */ 3 + /* Interrupt Controller Data */ 3;
//
// assert_eq!(interrupt_map.len() % (4 * cells_per_imap), 0);
//
// let mut imap = BTreeMap::new();
//
// for i in 0..interrupt_map.len() / (4 * cells_per_imap) {
// let pci_address_0 = interrupt_map
// .cell1_array_item(i * cells_per_imap, 1)
// .unwrap();
//
// let bus = (pci_address_0 >> 24) as u8;
// let device = ((pci_address_0 >> 11) & 0x1F) as u8;
// let function = ((pci_address_0 >> 8) & 0x7) as u8;
//
// let address = PciAddress::for_function(0, bus, device, function);
//
// let pin = interrupt_map
// .cell1_array_item(i * cells_per_imap + pci_address_cells, 1)
// .unwrap() as u32;
//
// let Ok(pin) = PciInterruptPin::try_from(pin) else {
// continue;
// };
//
// let _interrupt_ty = interrupt_map
// .cell1_array_item(i * cells_per_imap + pci_address_cells + 4, 1)
// .unwrap();
// let interrupt_number = interrupt_map
// .cell1_array_item(i * cells_per_imap + pci_address_cells + 5, 1)
// .unwrap();
// let interrupt_mode = interrupt_map
// .cell1_array_item(i * cells_per_imap + pci_address_cells + 6, 1)
// .unwrap();
//
// let (trigger, level) = match interrupt_mode {
// 0x04 => (IrqTrigger::Level, IrqLevel::ActiveHigh),
// _ => todo!(),
// };
//
// let src = PciInterrupt { address, pin };
// let dst = PciInterruptRoute {
// number: interrupt_number as _,
// options: IrqOptions { trigger, level },
// };
//
// // TODO use phandle for interrupt-controller
// // TODO interrupt-controller-specific decoding of idata
// // TODO don't ignore interrupt_ty, don't assume they're all SPIs
// imap.insert(src, dst);
// }
//
// imap
// }
#[derive(Debug)]
struct RangeProperties {
space: PciRangeType,
bus: u8,
}
impl From<u32> for RangeProperties {
fn from(value: u32) -> Self {
let s = (value >> 24) & 0x3;
let bus = (value >> 16) as u8;
let space = match s {
0 => PciRangeType::Configuration,
1 => PciRangeType::Io,
2 => PciRangeType::Memory32,
3 => PciRangeType::Memory64,
_ => unreachable!(),
};
Self { space, bus }
}
}
fn make_range(
context: &ProbeContext,
options: RangeProperties,
pci_base: u64,
host_base: u64,
size: u64,
) -> Option<PciAddressRange> {
let host_range = host_base..host_base + size;
let host_base = PhysicalAddress::from_u64(context.map_range(host_range)?.start);
let size = size.try_into().ok()?;
Some(PciAddressRange {
ty: options.space,
bus_number: options.bus,
host_base,
pci_base,
size,
})
}
fn make_interrupt_map(node: &Arc<Node>) -> Option<BTreeMap<PciInterrupt, PciInterruptRoute>> {
let map = node.property("interrupt-map")?;
let child_address_cells = node.self_address_cells()?.checked_sub(1)?;
let mut offset = 0;
let len = map.len() / size_of::<u32>();
let mut imap = BTreeMap::new();
while offset < len {
// TODO handle interrupt-map-mask
// interrupt-map:
// * PCI address + flags
// * Pin
// * Interrupt Controller Handle (phandle + 2 cells of ???)
// * Interrupt Controller Data (3 cells)
let address = map.read_cell(offset, 1)?;
offset += 1 + child_address_cells;
let (pin, phandle) = map.read_cells_at(offset, (1, 1))?;
// pin + phandle + whatever 2 cells of garbage go after phandle
offset += 4;
let interrupt_controller = interrupt_controller(phandle as u32)?;
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
let irq = map_interrupt_at(&interrupt_controller, &map, offset)?;
let bus = (address >> 24) as u8;
let device = ((address >> 11) & 0x1F) as u8;
let function = ((address >> 8) & 0x7) as u8;
let address = PciAddress::for_function(0, bus, device, function);
let pin = PciInterruptPin::try_from(pin as u32).ok()?;
let options = irq.options;
let Irq::External(irq) = irq.irq else {
todo!();
};
let src = PciInterrupt { address, pin };
// TODO specify interrupt controller for PCIe interrupts
let dst = PciInterruptRoute {
number: irq,
options,
};
imap.insert(src, dst);
offset += interrupt_cells;
}
Some(imap)
}
device_tree_driver! {
compatible: ["pci-host-ecam-generic"],
probe(dt) => {
loop {}
// let reg = dt::find_prop(&dt.node, "reg")?;
// let bus_range = dt::find_prop(&dt.node, "bus-range")?;
driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
let ecam_base = node.map_base(context, 0)?;
let ranges = node.property("ranges")?;
// let (cfg_space_base, _) = reg
// .cell2_array_item(0, dt.address_cells, dt.size_cells)
// .unwrap();
// let cfg_space_base = PhysicalAddress::from_u64(cfg_space_base);
let parent_address_cells = node.bus_address_cells();
let child_address_cells = node.self_address_cells()?.checked_sub(1)?;
let child_size_cells = node.self_size_cells()?;
// let bus_start = bus_range.cell1_array_item(0, 1)? as u8;
// let bus_end = bus_range.cell1_array_item(1, 1)? as u8;
// Extract interupt map
let interrupt_map = make_interrupt_map(node)?;
// let ranges = extract_ranges(dt);
// let interrupt_map = extract_interrupt_map(dt);
let cell_sizes = (1, child_address_cells, parent_address_cells, child_size_cells);
// if ranges.is_empty() {
// return None;
// }
// Extract PCI ranges
let mut bus_ranges = Vec::new();
for (flags, child_base, parent_base, size) in ranges.iter_cells(cell_sizes) {
let options = RangeProperties::from(flags as u32);
// PciBusManager::add_segment_from_device_tree(
// cfg_space_base,
// bus_start..bus_end,
// ranges,
// interrupt_map
// ).ok();
if let Some(range) = make_range(context, options, child_base, parent_base, size) {
log::info!(
"PCIe: {:#x?} -> {}:{:#x?}, {:?}",
range.host_base.into_u64()..range.host_base.into_u64() + range.size as u64,
range.bus_number,
range.pci_base..range.pci_base + range.size as u64,
range.ty
);
bus_ranges.push(range);
}
}
// None
PciBusManager::add_segment_from_device_tree(
ecam_base,
// TODO bus-range
0..255,
bus_ranges,
interrupt_map
).ok();
None
}
}
}

View File

@ -1,6 +1,6 @@
//! Bus devices
// #[cfg(any(target_arch = "aarch64", rust_analyzer))]
// pub mod dt_pci;
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod dt_pci;
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod simple_bus;

View File

@ -3,22 +3,18 @@
// use device_tree::{device_tree_driver, dt::DevTreeIndexNodeExt};
// use libk::device::manager::DEVICE_REGISTRY;
use core::{
ops::Range,
sync::atomic::{AtomicBool, Ordering},
};
use core::ops::Range;
use abi::error::Error;
use alloc::{sync::Arc, vec::Vec};
use device_api::{bus::Bus, device::Device};
use device_tree::{
driver::{device_tree_driver, register_bus, Node},
driver::{device_tree_driver, Node, ProbeContext},
dt::DevTreeIndexPropExt,
};
struct SimpleBus {
ranges: Vec<(Range<u64>, u64)>,
node: Node,
}
impl Device for SimpleBus {
@ -26,70 +22,58 @@ impl Device for SimpleBus {
Ok(())
}
fn as_bus(self: Arc<Self>) -> Option<Arc<dyn Bus>> {
Some(self)
}
fn display_name(&self) -> &str {
"simple-bus"
}
}
impl Bus for SimpleBus {
fn map_range(&self, bus_range: Range<u64>) -> Result<Range<u64>, Error> {
for (range, offset) in self.ranges.iter() {
if range.contains(&bus_range.start) {
let base = bus_range.start - range.start + *offset;
let size = bus_range.end - bus_range.start;
return Ok(base..base + size);
}
}
Err(Error::DoesNotExist)
}
fn map_range(&self, bus_range: Range<u64>) -> Option<Range<u64>> {
let start = bus_range.start;
let end = bus_range.end;
fn enumerate(&self, handler: fn(Arc<dyn Device>)) {
log::info!("Enumerating simple-bus {:?}", self.node.name());
for child in self.node.children() {
if let Some(device) = child.probe() {
handler(device);
for (range, offset) in self.ranges.iter() {
if range.contains(&start) && range.contains(&end) {
let start = start - range.start + *offset;
let end = end - range.start + *offset;
return Some(start..end);
}
}
None
}
}
// TODO support nested busses?
// TODO better initialization sequence for device tree nodes
static SIMPLE_BUS_DISCOVERED: AtomicBool = AtomicBool::new(false);
device_tree_driver! {
compatible: ["simple-bus"],
probe(of) => {
if SIMPLE_BUS_DISCOVERED.swap(true, Ordering::Acquire) {
return None;
driver: {
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> {
// Format per DT spec: (child-bus-address, parent-bus-address, length)
// Where:
// child-bus-address: #address-cells of this node
// parent-bus-address: #address-cells of parent bus
// length: #size-cells of this node
let ranges = node.property("ranges")?;
let parent_address_cells = node.bus_address_cells();
let child_address_cells = node.self_address_cells()?;
let child_size_cells = node.self_size_cells()?;
let cell_sizes = (child_address_cells, parent_address_cells, child_size_cells);
let mut items = Vec::new();
for (child_address, parent_address, length) in ranges.iter_cells(cell_sizes) {
let child_range = child_address..child_address + length;
items.push((child_range, parent_address));
}
Some(Arc::new(SimpleBus {
ranges: items,
}))
}
// Format per DT spec: (child-bus-address, parent-bus-address, length)
// Where:
// child-bus-address: #address-cells of this node
// parent-bus-address: #address-cells of parent bus
// length: #size-cells of this node
let ranges = of.property("ranges")?;
let parent_address_cells = of.parent_address_cells();
let child_address_cells = of.self_address_cells()?;
let child_size_cells = of.self_size_cells()?;
let cell_sizes = (child_address_cells, parent_address_cells, child_size_cells);
let mut items = Vec::new();
for (child_address, parent_address, length) in ranges.iter_cells(cell_sizes) {
let child_range = child_address..child_address + length;
items.push((child_range, parent_address));
}
let bus = Arc::new(SimpleBus {
ranges: items,
node: of.clone(),
});
register_bus(bus.clone(), bus.ranges.iter().map(|(a, _)| a.clone()));
Some(bus)
}
}

View File

@ -2,8 +2,6 @@
// TODO
#![allow(missing_docs)]
use core::sync::atomic::{AtomicBool, Ordering};
use abi::{
error::Error,
io::{TerminalOptions, TerminalOutputOptions},
@ -11,9 +9,9 @@ use abi::{
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq, IrqLevel, IrqOptions, IrqTrigger},
interrupt::{FullIrq, InterruptHandler},
};
use device_tree::driver::device_tree_driver;
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::{DebugSink, LogLevel},
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
@ -65,7 +63,7 @@ struct Inner {
pub struct Bcm2835AuxUart {
base: PhysicalAddress,
irq: Irq,
irq: FullIrq,
inner: OneTimeInit<Arc<Terminal<Inner>>>,
}
@ -167,7 +165,7 @@ impl Device for Bcm2835AuxUart {
DEVICE_REGISTRY
.serial_terminal
.register(inner.clone(), Some((self.clone(), LogLevel::Info)))
.register(inner.clone(), Some((self.clone(), LogLevel::Debug)))
.ok();
Ok(())
@ -175,15 +173,8 @@ impl Device for Bcm2835AuxUart {
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(
self.irq,
IrqOptions {
trigger: IrqTrigger::Level,
level: IrqLevel::ActiveLow,
},
self.clone(),
)?;
intc.enable_irq(self.irq)?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
let inner = self.inner.get().output();
let regs = inner.regs.lock();
@ -199,24 +190,20 @@ impl Device for Bcm2835AuxUart {
}
}
// TODO handle interrupt-parent
// TODO handle pinctrl
// TODO handle clock
// TODO fix issue with duplicate initialization
static AUX_UART_DISCOVERED: AtomicBool = AtomicBool::new(false);
device_tree_driver! {
compatible: ["brcm,bcm2835-aux-uart"],
probe(of) => {
if AUX_UART_DISCOVERED.swap(true, Ordering::Relaxed) {
return None;
driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?;
Some(Arc::new(Bcm2835AuxUart {
base,
irq,
inner: OneTimeInit::new(),
}))
}
let range = of.mapped_range(0)?;
let base = PhysicalAddress::from_u64(range.start);
let irq = Irq::External(93);
Some(Arc::new(Bcm2835AuxUart {
base,
irq,
inner: OneTimeInit::new()
}))
}
}

View File

@ -1,12 +1,7 @@
//! Serial device interfaces
// Raspberry Pi
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod bcm2835_aux_uart;
// TODO temporarily disabled for raspi4b
#[cfg(any(
all(target_arch = "aarch64", not(feature = "aarch64_board_raspi4b")),
rust_analyzer
))]
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod pl011;

View File

@ -1,13 +1,11 @@
//! ARM PL011 driver
use core::sync::atomic::{AtomicBool, Ordering};
use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq},
interrupt::{FullIrq, InterruptHandler},
};
use device_tree::driver::device_tree_driver;
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::{DebugSink, LogLevel},
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
@ -71,7 +69,7 @@ struct Pl011Inner {
pub struct Pl011 {
inner: OneTimeInit<Arc<Terminal<Pl011Inner>>>,
base: PhysicalAddress,
irq: Irq,
irq: FullIrq,
}
impl Io {
@ -160,7 +158,7 @@ impl Device for Pl011 {
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some((self.clone(), LogLevel::Info)))
.register(terminal.clone(), Some((self.clone(), LogLevel::Debug)))
.ok();
Ok(())
@ -169,33 +167,29 @@ impl Device for Pl011 {
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq, Default::default(), self.clone())?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
{
let io = self.inner.get().output().io.lock();
io.regs.IMSC.modify(IMSC::RXIM::SET);
}
intc.enable_irq(self.irq)?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
}
// TODO prevent double initialization
static PL011_DISCOVERED: AtomicBool = AtomicBool::new(false);
device_tree_driver! {
compatible: ["arm,pl011"],
probe(of) => {
if PL011_DISCOVERED.swap(true, Ordering::Acquire) {
return None;
}
let range = of.mapped_range(0)?;
let base = PhysicalAddress::from_u64(range.start);
let irq = Irq::External(1);
Some(Arc::new(Pl011 {
base,
irq,
inner: OneTimeInit::new()
}))
driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?;
Some(Arc::new(Pl011 {
base,
irq,
inner: OneTimeInit::new(),
}))
}
}
}