Skip to content

Commit

Permalink
Merge pull request #402 from hermit-os/fdt
Browse files Browse the repository at this point in the history
refactor: unify FDT creation
  • Loading branch information
mkroening authored Nov 16, 2024
2 parents 6aebe82 + 9e655bd commit e159762
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 150 deletions.
32 changes: 6 additions & 26 deletions src/arch/x86_64/multiboot.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use alloc::format;
use core::ptr::write_bytes;
use core::{mem, ptr, slice};

Expand All @@ -8,14 +7,15 @@ use hermit_entry::boot_info::{
};
use hermit_entry::elf::LoadedKernel;
use log::info;
use multiboot::information::{MemoryManagement, MemoryType, Multiboot, PAddr};
use multiboot::information::{MemoryManagement, Multiboot, PAddr};
use sptr::Strict;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_fdt::FdtWriterResult;
use x86_64::structures::paging::{PageSize, PageTableFlags, Size2MiB, Size4KiB};

use super::paging;
use super::physicalmem::PhysAlloc;
use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT};
use crate::fdt::Fdt;
use crate::BootInfoExt;

extern "C" {
Expand Down Expand Up @@ -55,36 +55,16 @@ impl DeviceTree {
let mut mem = Mem;
let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() };

let all_regions = multiboot
let memory_regions = multiboot
.memory_regions()
.expect("Could not find a memory map in the Multiboot information");
let ram_regions = all_regions.filter(|m| m.memory_type() == MemoryType::Available);

let mut fdt = FdtWriter::new()?;

let root_node = fdt.begin_node("")?;
fdt.property_string("compatible", "linux,dummy-virt")?;
fdt.property_u32("#address-cells", 0x2)?;
fdt.property_u32("#size-cells", 0x2)?;
let mut fdt = Fdt::new("multiboot")?.memory_regions(memory_regions)?;

if let Some(cmdline) = multiboot.command_line() {
let chosen_node = fdt.begin_node("chosen")?;
fdt.property_string("bootargs", cmdline)?;
fdt.end_node(chosen_node)?;
fdt = fdt.bootargs(cmdline)?;
}

for m in ram_regions {
let start_address = m.base_address();
let length = m.length();

let memory_node = fdt.begin_node(format!("memory@{:x}", start_address).as_str())?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &[start_address, length])?;
fdt.end_node(memory_node)?;
}

fdt.end_node(root_node)?;

let fdt = fdt.finish()?;

Ok(fdt.leak())
Expand Down
181 changes: 181 additions & 0 deletions src/fdt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use alloc::format;
use alloc::vec::Vec;
use core::ops::Range;

use vm_fdt::{FdtWriter, FdtWriterNode, FdtWriterResult};

pub struct Fdt<'a> {
writer: FdtWriter,
root_node: FdtWriterNode,
bootargs: Option<&'a str>,
}

impl<'a> Fdt<'a> {
pub fn new(platform: &str) -> FdtWriterResult<Self> {
let mut writer = FdtWriter::new()?;

let root_node = writer.begin_node("")?;
writer.property_string("compatible", &format!("hermit,{platform}"))?;
writer.property_u32("#address-cells", 0x2)?;
writer.property_u32("#size-cells", 0x2)?;

let bootargs = None;

Ok(Self {
writer,
root_node,
bootargs,
})
}

pub fn finish(mut self) -> FdtWriterResult<Vec<u8>> {
let chosen_node = self.writer.begin_node("chosen")?;
if let Some(bootargs) = self.bootargs {
self.writer.property_string("bootargs", bootargs)?;
}
self.writer.end_node(chosen_node)?;

self.writer.end_node(self.root_node)?;

self.writer.finish()
}

#[cfg_attr(target_os = "uefi", expect(unused))]
pub fn bootargs(mut self, bootargs: &'a str) -> FdtWriterResult<Self> {
assert!(self.bootargs.is_none());
self.bootargs = Some(bootargs);

Ok(self)
}

#[cfg_attr(all(target_arch = "x86_64", not(target_os = "uefi")), expect(unused))]
pub fn rsdp(mut self, rsdp: u64) -> FdtWriterResult<Self> {
let rsdp_node = self.writer.begin_node(&format!("hermit,rsdp@{rsdp:x}"))?;
self.writer.property_array_u64("reg", &[rsdp, 1])?;
self.writer.end_node(rsdp_node)?;

Ok(self)
}

pub fn memory(mut self, memory: Range<u64>) -> FdtWriterResult<Self> {
let memory_node = self
.writer
.begin_node(format!("memory@{:x}", memory.start).as_str())?;
self.writer.property_string("device_type", "memory")?;
self.writer
.property_array_u64("reg", &[memory.start, memory.end - memory.start])?;
self.writer.end_node(memory_node)?;

Ok(self)
}
}

#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(feature = "fc")))]
mod x86_64 {
use multiboot::information::{MemoryMapIter, MemoryType};
use vm_fdt::FdtWriterResult;

impl super::Fdt<'_> {
pub fn memory_regions(
mut self,
memory_regions: MemoryMapIter<'_, '_>,
) -> FdtWriterResult<Self> {
let memory_regions =
memory_regions.filter(|m| m.memory_type() == MemoryType::Available);

for memory_region in memory_regions {
self = self.memory(
memory_region.base_address()
..memory_region.base_address() + memory_region.length(),
)?;
}

Ok(self)
}
}
}

#[cfg(target_os = "uefi")]
mod uefi {
use core::fmt;
use core::fmt::Write;

use log::info;
use uefi::boot::{MemoryDescriptor, MemoryType, PAGE_SIZE};
use uefi::mem::memory_map::{MemoryMap, MemoryMapMut};
use vm_fdt::FdtWriterResult;

impl super::Fdt<'_> {
pub fn memory_map(mut self, memory_map: &mut impl MemoryMapMut) -> FdtWriterResult<Self> {
memory_map.sort();
info!("Memory map:\n{}", memory_map.display());

let entries = memory_map
.entries()
.filter(|entry| entry.ty == MemoryType::CONVENTIONAL);

for entry in entries {
self = self.memory(
entry.phys_start..entry.phys_start + entry.page_count * PAGE_SIZE as u64,
)?;
}

Ok(self)
}
}

trait MemoryMapExt: MemoryMap {
fn display(&self) -> MemoryMapDisplay<'_, Self> {
MemoryMapDisplay { inner: self }
}
}

impl<T> MemoryMapExt for T where T: MemoryMap {}

struct MemoryMapDisplay<'a, T: ?Sized> {
inner: &'a T,
}

impl<'a, T> fmt::Display for MemoryMapDisplay<'a, T>
where
T: MemoryMap,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut has_fields = false;

for desc in self.inner.entries() {
if has_fields {
f.write_char('\n')?;
}
write!(f, "{}", desc.display())?;

has_fields = true;
}
Ok(())
}
}

trait MemoryDescriptorExt {
fn display(&self) -> MemoryDescriptorDisplay<'_>;
}

impl MemoryDescriptorExt for MemoryDescriptor {
fn display(&self) -> MemoryDescriptorDisplay<'_> {
MemoryDescriptorDisplay { inner: self }
}
}

struct MemoryDescriptorDisplay<'a> {
inner: &'a MemoryDescriptor,
}

impl<'a> fmt::Display for MemoryDescriptorDisplay<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"start: {:#12x}, pages: {:#8x}, type: {:?}",
self.inner.phys_start, self.inner.page_count, self.inner.ty
)
}
}
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ mod macros;

mod arch;
mod bump_allocator;
#[cfg(any(target_os = "uefi", all(target_arch = "x86_64", not(feature = "fc"))))]
mod fdt;
mod log;
mod os;

Expand Down
121 changes: 0 additions & 121 deletions src/os/uefi/fdt.rs

This file was deleted.

Loading

0 comments on commit e159762

Please sign in to comment.