Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 161 additions & 157 deletions src/arch/riscv64/kernel/devicetree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,179 +109,183 @@ pub fn init_drivers(handlers: &mut InterruptHandlerMap) {
if let Some(fdt) = env::fdt() {
debug!("Init drivers using devicetree");

unsafe {
// Init PLIC first
if let Some(plic_node) = fdt.find_compatible(&["sifive,plic-1.0.0"]) {
debug!("Found interrupt controller");
let plic_region = plic_node
.reg()
.expect("Reg property for PLIC not found in FDT")
.next()
.unwrap();

let plic_region_start = PhysAddr::from(plic_region.starting_address.addr());
debug!(
"Init PLIC at {:p}, size: {:x}",
plic_region_start,
plic_region.size.unwrap()
);
assert!(
plic_region.size.unwrap()
< usize::try_from(paging::HugePageSize::SIZE).unwrap()
);

paging::identity_map::<paging::HugePageSize>(plic_region_start);

// TODO: Determine correct context via devicetree and allow more than one context
let context = match PLATFORM_MODEL {
// Init PLIC first
if let Some(plic_node) = fdt.find_compatible(&["sifive,plic-1.0.0"]) {
debug!("Found interrupt controller");
let plic_region = plic_node
.reg()
.expect("Reg property for PLIC not found in FDT")
.next()
.unwrap();

let plic_region_start = PhysAddr::from(plic_region.starting_address.addr());
debug!(
"Init PLIC at {:p}, size: {:x}",
plic_region_start,
plic_region.size.unwrap()
);
assert!(
plic_region.size.unwrap() < usize::try_from(paging::HugePageSize::SIZE).unwrap()
);

paging::identity_map::<paging::HugePageSize>(plic_region_start);

// TODO: Determine correct context via devicetree and allow more than one context
let context = unsafe {
match PLATFORM_MODEL {
Model::Virt | Model::Unknown => 1,
Model::Fux40 => 2,
};
init_plic(plic_region.starting_address, context);
}
};
init_plic(plic_region.starting_address, context);
}

// Init GEM
#[cfg(all(feature = "gem-net", not(feature = "pci")))]
if let Some(gem_node) = fdt.find_compatible(&["sifive,fu540-c000-gem"]) {
debug!("Found Ethernet controller");

let gem_region = gem_node
.reg()
.expect("reg property for GEM not found in FDT")
.next()
.unwrap();
let irq = gem_node
.interrupts()
.expect("interrupts property for GEM not found in FDT")
.next()
.unwrap();
let mac = gem_node
.property("local-mac-address")
.expect("local-mac-address property for GEM not found in FDT")
.value;
debug!("Local MAC address: {mac:x?}");
let mut phy_addr = u32::MAX;

let phy_node = gem_node
.children()
.next()
.expect("GEM node has no child node (i. e. ethernet-phy)");
if phy_node.name.contains("ethernet-phy") {
phy_addr = phy_node
.property("reg")
.expect("reg property for ethernet-phy not found in FDT")
.as_usize()
.unwrap() as u32;
} else {
warn!("Expected ethernet-phy node, found something else");
}

// Init GEM
#[cfg(all(feature = "gem-net", not(feature = "pci")))]
if let Some(gem_node) = fdt.find_compatible(&["sifive,fu540-c000-gem"]) {
debug!("Found Ethernet controller");

let gem_region = gem_node
.reg()
.expect("reg property for GEM not found in FDT")
.next()
.unwrap();
let irq = gem_node
.interrupts()
.expect("interrupts property for GEM not found in FDT")
.next()
.unwrap();
let mac = gem_node
.property("local-mac-address")
.expect("local-mac-address property for GEM not found in FDT")
.value;
debug!("Local MAC address: {mac:x?}");
let mut phy_addr = u32::MAX;

let phy_node = gem_node
.children()
.next()
.expect("GEM node has no child node (i. e. ethernet-phy)");
if phy_node.name.contains("ethernet-phy") {
phy_addr = phy_node
.property("reg")
.expect("reg property for ethernet-phy not found in FDT")
.as_usize()
.unwrap() as u32;
} else {
warn!("Expected ethernet-phy node, found something else");
}
let gem_region_start = PhysAddr::from(gem_region.starting_address.expose_provenance());
debug!("Init GEM at {gem_region_start:p}, irq: {irq}, phy_addr: {phy_addr}");
assert!(
gem_region.size.unwrap() < usize::try_from(paging::HugePageSize::SIZE).unwrap()
);
paging::identity_map::<paging::HugePageSize>(gem_region_start);
match gem::init_device(
VirtAddr::new(gem_region_start.as_u64()),
irq.try_into().unwrap(),
phy_addr,
<[u8; 6]>::try_from(mac).expect("MAC with invalid length"),
handlers,
) {
Ok(drv) => *NETWORK_DEVICE.lock() = Some(drv),
Err(err) => error!("Could not initialize GEM driver: {err}"),
}
}

let gem_region_start =
PhysAddr::from(gem_region.starting_address.expose_provenance());
debug!("Init GEM at {gem_region_start:p}, irq: {irq}, phy_addr: {phy_addr}");
assert!(
gem_region.size.unwrap() < usize::try_from(paging::HugePageSize::SIZE).unwrap()
);
paging::identity_map::<paging::HugePageSize>(gem_region_start);
match gem::init_device(
VirtAddr::new(gem_region_start.as_u64()),
irq.try_into().unwrap(),
phy_addr,
<[u8; 6]>::try_from(mac).expect("MAC with invalid length"),
handlers,
) {
Ok(drv) => *NETWORK_DEVICE.lock() = Some(drv),
Err(err) => error!("Could not initialize GEM driver: {err}"),
}
// Init virtio-mmio
#[cfg(all(feature = "virtio", not(feature = "pci")))]
for virtio_node in fdt.all_nodes() {
let is_virtio_mmio = virtio_node
.compatible()
.is_some_and(|c| c.all().any(|x| x == "virtio,mmio"));
if !is_virtio_mmio {
continue;
}
debug!("Found virtio mmio device");

let virtio_region = virtio_node
.reg()
.expect("reg property for virtio mmio not found in FDT")
.next()
.unwrap();
let irq = virtio_node
.interrupts()
.expect("interrupts property for virtio mmio not found in FDT")
.next()
.unwrap();

let virtio_region_start =
PhysAddr::from(virtio_region.starting_address.expose_provenance());

debug!("Init virtio_mmio at {virtio_region_start:p}, irq: {irq}");
assert!(
virtio_region.size.unwrap() < usize::try_from(paging::HugePageSize::SIZE).unwrap()
);
paging::identity_map::<paging::HugePageSize>(virtio_region_start);

// Verify the first register value to find out if this is really an MMIO magic-value.
let ptr = virtio_region.starting_address as *mut DeviceRegisters;
let mmio = unsafe { VolatileRef::new(NonNull::new(ptr).unwrap()) };

let magic = mmio.as_ptr().magic_value().read().to_ne();
let version = mmio.as_ptr().version().read().to_ne();

const MMIO_MAGIC_VALUE: u32 = 0x7472_6976;
if magic != MMIO_MAGIC_VALUE {
error!("It's not a MMIO-device at {mmio:p}");
}

// Init virtio-mmio
#[cfg(all(feature = "virtio", not(feature = "pci")))]
if let Some(virtio_node) = fdt.find_compatible(&["virtio,mmio"]) {
debug!("Found virtio mmio device");
let virtio_region = virtio_node
.reg()
.expect("reg property for virtio mmio not found in FDT")
.next()
.unwrap();
let irq = virtio_node
.interrupts()
.expect("interrupts property for virtio mmio not found in FDT")
.next()
.unwrap();

let virtio_region_start =
PhysAddr::from(virtio_region.starting_address.expose_provenance());

debug!("Init virtio_mmio at {virtio_region_start:p}, irq: {irq}");
assert!(
virtio_region.size.unwrap()
< usize::try_from(paging::HugePageSize::SIZE).unwrap()
);
paging::identity_map::<paging::HugePageSize>(virtio_region_start);

// Verify the first register value to find out if this is really an MMIO magic-value.
let ptr = virtio_region.starting_address as *mut DeviceRegisters;
let mmio = VolatileRef::new(NonNull::new(ptr).unwrap());

let magic = mmio.as_ptr().magic_value().read().to_ne();
let version = mmio.as_ptr().version().read().to_ne();

const MMIO_MAGIC_VALUE: u32 = 0x7472_6976;
if magic != MMIO_MAGIC_VALUE {
error!("It's not a MMIO-device at {mmio:p}");
}
if version != 2 {
warn!("Found a legacy device, which isn't supported");
return;
}

if version != 2 {
warn!("Found a legacy device, which isn't supported");
return;
}
// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {mmio:p}");

// Verify the device-ID to find the network card
let id = mmio.as_ptr().device_id().read();

// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {mmio:p}");
if cfg!(debug_assertions) {
use free_list::PageRange;

// Verify the device-ID to find the network card
let id = mmio.as_ptr().device_id().read();
use crate::mm::{FrameAlloc, PageRangeAllocator};

if cfg!(debug_assertions) {
use free_list::PageRange;
let start = virtio_region.starting_address.addr();
let len = virtio_region.size.unwrap();
let frame_range = PageRange::from_start_len(start, len).unwrap();

use crate::mm::{FrameAlloc, PageRangeAllocator};
FrameAlloc::allocate_at(frame_range).unwrap_err();
}

let start = virtio_region.starting_address.addr();
let len = virtio_region.size.unwrap();
let frame_range = PageRange::from_start_len(start, len).unwrap();
debug!("Found virtio {id:?} at {mmio:p}");

FrameAlloc::allocate_at(frame_range).unwrap_err();
match mmio_virtio::init_device(mmio, irq.try_into().unwrap(), handlers) {
#[cfg(feature = "virtio-console")]
Ok(VirtioDriver::Console(drv)) => {
register_driver(MmioDriver::VirtioConsole(
hermit_sync::InterruptSpinMutex::new(*drv),
));
}

debug!("Found virtio {id:?} at {mmio:p}");

match mmio_virtio::init_device(mmio, irq.try_into().unwrap(), handlers) {
#[cfg(feature = "virtio-console")]
Ok(VirtioDriver::Console(drv)) => {
register_driver(MmioDriver::VirtioConsole(
hermit_sync::InterruptSpinMutex::new(*drv),
));
}
#[cfg(feature = "virtio-fs")]
Ok(VirtioDriver::Fs(drv)) => {
register_driver(MmioDriver::VirtioFs(
hermit_sync::InterruptSpinMutex::new(*drv),
));
}
#[cfg(feature = "virtio-net")]
Ok(VirtioDriver::Net(drv)) => {
*NETWORK_DEVICE.lock() = Some(*drv);
}
#[cfg(feature = "virtio-vsock")]
Ok(VirtioDriver::Vsock(drv)) => {
register_driver(MmioDriver::VirtioVsock(
hermit_sync::InterruptSpinMutex::new(*drv),
));
}
Err(err) => error!("Could not initialize virtio-mmio device: {err}"),
#[cfg(feature = "virtio-fs")]
Ok(VirtioDriver::Fs(drv)) => {
register_driver(MmioDriver::VirtioFs(hermit_sync::InterruptSpinMutex::new(
*drv,
)));
}
#[cfg(feature = "virtio-net")]
Ok(VirtioDriver::Net(drv)) => {
*NETWORK_DEVICE.lock() = Some(*drv);
}
#[cfg(feature = "virtio-vsock")]
Ok(VirtioDriver::Vsock(drv)) => {
register_driver(MmioDriver::VirtioVsock(
hermit_sync::InterruptSpinMutex::new(*drv),
));
}
Err(err) => error!("Could not initialize virtio-mmio device: {err}"),
}
}
}
Expand Down
Loading