From 826a122241eb5fc4326c75cacc6b3b7451ab6500 Mon Sep 17 00:00:00 2001 From: Bryan McShea Date: Wed, 24 Apr 2024 20:44:23 -0400 Subject: [PATCH] actually good fdt formatting --- kernel/.cargo/config.toml | 2 +- kernel/src/dev/fdt.rs | 241 +++++------ kernel/src/dev/mem.rs | 57 +++ kernel/src/dev/mod.rs | 3 +- kernel/stuff | 879 ++++++++++++++++++++++++++++++++++++++ kernel/test.raw | Bin 1073741824 -> 104857600 bytes 6 files changed, 1036 insertions(+), 146 deletions(-) create mode 100644 kernel/src/dev/mem.rs create mode 100644 kernel/stuff diff --git a/kernel/.cargo/config.toml b/kernel/.cargo/config.toml index 7c4343d..0b867da 100644 --- a/kernel/.cargo/config.toml +++ b/kernel/.cargo/config.toml @@ -8,7 +8,7 @@ rustflags = [ "-C", "link-arg=-Tsrc/arch/riscv64/link.ld", "-C", "link-arg=--omagic", ] -runner = "qemu-system-riscv64 -nographic -semihosting -cpu rv64 -machine virt -bios none -smp 4 -m 1G -drive file=test.raw,format=raw -kernel" +runner = "qemu-system-riscv64 -nographic -semihosting -cpu rv64 -machine virt -bios none -smp 4 -m 1G -device virtio-blk-pci,drive=test -drive file=test.raw,format=raw,id=test -kernel" [unstable] build-std = ["core", "compiler_builtins", "alloc"] diff --git a/kernel/src/dev/fdt.rs b/kernel/src/dev/fdt.rs index 7222241..cadc5e4 100644 --- a/kernel/src/dev/fdt.rs +++ b/kernel/src/dev/fdt.rs @@ -4,12 +4,7 @@ use crate::{ println, util::bits::{u32_from_bytes, Be}, }; -use core::{ - fmt::Debug, - mem::{size_of, transmute}, - ops::Range, - slice, -}; +use core::{fmt::Debug, mem::size_of, slice}; const MAGIC: u32 = 0xd00dfeed; @@ -35,7 +30,6 @@ impl Token { 0x00000004 => Token::Nop, 0x00000009 => Token::End, _ => { - println!("Failed to parse token!"); return None; } }) @@ -62,6 +56,74 @@ pub struct RawProp { nameoff: Be, } +pub struct FDT { + pub header: &'static Header, + pub nodes: &'static [u8], + pub strings: &'static [u8], +} + +impl FDT { + pub fn nodes(&self) -> NodeIter { + NodeIter { + pos: self.nodes, + strings: self.strings, + } + } + pub unsafe fn from_addr(addr: *mut u8) -> Self { + let header: &Header = &*(addr as *const Header); + if header.magic.get() != MAGIC { + panic!("fdt magic wrong"); + } + let data = slice::from_raw_parts(addr, header.totalsize.get() as usize); + Self { + header, + nodes: &data[header.off_dt_struct.get() as usize..], + strings: &data[header.off_dt_strings.get() as usize..], + } + } +} + +pub struct Node { + pub name: &'static str, + pub strings: &'static [u8], + pub props: &'static [u8], + pub children: &'static [u8], +} + +impl Debug for Node { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut fmt = f.debug_struct(self.name); + for prop in self.props() { + fmt.field(prop.name, &prop.data.len()); + } + for child in self.children() { + fmt.field(" - child", &child); + } + fmt.finish() + } +} + +impl Node { + pub fn children(&self) -> NodeIter { + NodeIter { + pos: self.children, + strings: self.strings, + } + } + pub fn child(&self, name: &str) -> Option { + self.children().find(|c| c.name == name) + } + pub fn props(&self) -> PropIter { + PropIter { + pos: self.props, + strings: self.strings, + } + } + pub fn prop(&self, name: &str) -> Option { + self.props().find(|p| p.name == name) + } +} + pub struct Prop { pub name: &'static str, pub data: &'static [u8], @@ -82,10 +144,35 @@ impl Prop { } } -pub struct FDT { - pub header: &'static Header, - pub nodes: &'static [u8], +pub struct PropIter { pub strings: &'static [u8], + pub pos: &'static [u8], +} + +impl Iterator for PropIter { + type Item = Prop; + fn next(&mut self) -> Option { + let token: Token = Token::from_bytes(self.pos)?; + let Token::Prop = token else { + return None; + }; + self.pos = &self.pos[4..]; + let prop: &RawProp = unsafe { &*(self.pos.as_ptr() as *const RawProp) }; + self.pos = &self.pos[PROP_SIZE..]; + let plen = prop.len.get() as usize; + let len = (plen + (TOKEN_SIZE - 1)) & !(TOKEN_SIZE - 1); + let data = &self.pos[..len]; + self.pos = &self.pos[len..]; + let name_start = &self.strings[prop.nameoff.get() as usize..]; + for (i, c) in name_start.iter().enumerate() { + if *c == 0 { + let name: &str = core::str::from_utf8(&name_start[..i]).expect("uhhhhh"); + return Some(Prop { name, data }); + } + } + println!("failed to read prop name, not sure what to do"); + None + } } pub struct NodeIter { @@ -165,137 +252,3 @@ impl Iterator for NodeIter { } } -impl FDT { - pub fn nodes(&self) -> NodeIter { - NodeIter { - pos: self.nodes, - strings: self.strings, - } - } - pub unsafe fn from_addr(addr: *mut u8) -> Self { - let header: &Header = &*(addr as *const Header); - if header.magic.get() != MAGIC { - panic!("fdt magic wrong"); - } - let data = slice::from_raw_parts(addr, header.totalsize.get() as usize); - Self { - header, - nodes: &data[header.off_dt_struct.get() as usize..], - strings: &data[header.off_dt_strings.get() as usize..], - } - } - pub fn mem_range(&self) -> FDTMemRange { - let root = self.nodes().next().unwrap(); - if let Some(node) = root.children().find(|n| n.name.starts_with("memory@")) { - let prop = node.find_prop("reg"); - if let Some(prop) = prop { - if let Some(d) = prop.data.chunks(size_of::()).next() { - let d: [u8; size_of::()] = d.try_into().unwrap(); - return unsafe { transmute::<[u8; 16], FDTMemRange>(d) }; - } - } - } - panic!("failed to get memory range"); - } -} - -#[repr(C)] -pub struct FDTMemRange { - pub start: Be<*mut u8>, - pub len: Be, -} - -impl FDTMemRange { - pub fn start(&self) -> *mut u8 { - self.start.get() - } - pub fn len(&self) -> usize { - self.len.get() - } - pub fn end(&self) -> *mut u8 { - unsafe { self.start().add(self.len.get()) } - } -} - -impl Debug for FDTMemRange { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "{:?}..{:?}", self.start(), self.end()) - } -} - -impl From for Range<*mut u8> { - fn from(val: FDTMemRange) -> Self { - Range { - start: val.start(), - end: val.end(), - } - } -} - -pub struct Node { - pub name: &'static str, - pub strings: &'static [u8], - pub props: &'static [u8], - pub children: &'static [u8], -} - -impl Debug for Node { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let props: alloc::vec::Vec<_> = self.props().collect(); - let children: alloc::vec::Vec<_> = self.children().collect(); - f.debug_struct("Node") - .field("name", &self.name) - .field("props", &props) - .field("children", &children) - .finish() - } -} - -impl Node { - pub fn children(&self) -> NodeIter { - NodeIter { - pos: self.children, - strings: self.strings, - } - } - pub fn props(&self) -> PropIter { - PropIter { - pos: self.props, - strings: self.strings, - } - } - pub fn find_prop(&self, name: &str) -> Option { - self.props().find(|p| p.name == name) - } -} - -pub struct PropIter { - pub strings: &'static [u8], - pub pos: &'static [u8], -} - -impl Iterator for PropIter { - type Item = Prop; - fn next(&mut self) -> Option { - let token: Token = Token::from_bytes(self.pos)?; - let Token::Prop = token else { - return None; - }; - self.pos = &self.pos[4..]; - let prop: &RawProp = unsafe { &*(self.pos.as_ptr() as *const RawProp) }; - self.pos = &self.pos[PROP_SIZE..]; - let plen = prop.len.get() as usize; - let len = (plen + (TOKEN_SIZE - 1)) & !(TOKEN_SIZE - 1); - let data = &self.pos[..len]; - self.pos = &self.pos[len..]; - let name_start = &self.strings[prop.nameoff.get() as usize..]; - for (i, c) in name_start.iter().enumerate() { - if *c == 0 { - let name: &str = core::str::from_utf8(&name_start[..i]).expect("uhhhhh"); - return Some(Prop { name, data }); - } - } - println!("failed to read prop name, not sure what to do"); - None - } -} diff --git a/kernel/src/dev/mem.rs b/kernel/src/dev/mem.rs new file mode 100644 index 0000000..d069d99 --- /dev/null +++ b/kernel/src/dev/mem.rs @@ -0,0 +1,57 @@ +use core::{ + fmt::Debug, + mem::{size_of, transmute}, + ops::Range, +}; + +use crate::util::bits::Be; + +use super::fdt::FDT; + +impl FDT { + pub fn mem_range(&self) -> FDTMemRange { + let root = self.nodes().next().unwrap(); + if let Some(node) = root.children().find(|n| n.name.starts_with("memory@")) { + if let Some(prop) = node.prop("reg") { + if let Some(d) = prop.data.chunks(size_of::()).next() { + let d: [u8; size_of::()] = d.try_into().unwrap(); + return unsafe { transmute::<[u8; 16], FDTMemRange>(d) }; + } + } + } + panic!("failed to get memory range"); + } +} + +#[repr(C)] +pub struct FDTMemRange { + pub start: Be<*mut u8>, + pub len: Be, +} + +impl FDTMemRange { + pub fn start(&self) -> *mut u8 { + self.start.get() + } + pub fn len(&self) -> usize { + self.len.get() + } + pub fn end(&self) -> *mut u8 { + unsafe { self.start().add(self.len.get()) } + } +} + +impl Debug for FDTMemRange { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}..{:?}", self.start(), self.end()) + } +} + +impl From for Range<*mut u8> { + fn from(val: FDTMemRange) -> Self { + Range { + start: val.start(), + end: val.end(), + } + } +} diff --git a/kernel/src/dev/mod.rs b/kernel/src/dev/mod.rs index 4c4ceb3..6668bff 100644 --- a/kernel/src/dev/mod.rs +++ b/kernel/src/dev/mod.rs @@ -1,2 +1,3 @@ -pub mod uart; pub mod fdt; +pub mod mem; +pub mod uart; diff --git a/kernel/stuff b/kernel/stuff new file mode 100644 index 0000000..915b634 --- /dev/null +++ b/kernel/stuff @@ -0,0 +1,879 @@ +we out here vibin +memory range: 0x81626000..0xc0000000 +Node { + name: "", + props: [ + Prop { + name: "#address-cells", + data_len: 4, + }, + Prop { + name: "#size-cells", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 16, + }, + Prop { + name: "model", + data_len: 20, + }, + ], + children: [ + Node { + name: "poweroff", + props: [ + Prop { + name: "value", + data_len: 4, + }, + Prop { + name: "offset", + data_len: 4, + }, + Prop { + name: "regmap", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 16, + }, + ], + children: [], + }, + Node { + name: "reboot", + props: [ + Prop { + name: "value", + data_len: 4, + }, + Prop { + name: "offset", + data_len: 4, + }, + Prop { + name: "regmap", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 16, + }, + ], + children: [], + }, + Node { + name: "platform-bus@4000000", + props: [ + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "ranges", + data_len: 16, + }, + Prop { + name: "#address-cells", + data_len: 4, + }, + Prop { + name: "#size-cells", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 28, + }, + ], + children: [], + }, + Node { + name: "memory@80000000", + props: [ + Prop { + name: "device_type", + data_len: 8, + }, + Prop { + name: "reg", + data_len: 16, + }, + ], + children: [], + }, + Node { + name: "cpus", + props: [ + Prop { + name: "#address-cells", + data_len: 4, + }, + Prop { + name: "#size-cells", + data_len: 4, + }, + Prop { + name: "timebase-frequency", + data_len: 4, + }, + ], + children: [ + Node { + name: "cpu@0", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "device_type", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 4, + }, + Prop { + name: "status", + data_len: 8, + }, + Prop { + name: "compatible", + data_len: 8, + }, + Prop { + name: "riscv,cboz-block-size", + data_len: 4, + }, + Prop { + name: "riscv,cbom-block-size", + data_len: 4, + }, + Prop { + name: "riscv,isa", + data_len: 124, + }, + Prop { + name: "mmu-type", + data_len: 12, + }, + ], + children: [ + Node { + name: "interrupt-controller", + props: [ + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + Prop { + name: "interrupt-controller", + data_len: 0, + }, + Prop { + name: "compatible", + data_len: 16, + }, + Prop { + name: "phandle", + data_len: 4, + }, + ], + children: [], + }, + ], + }, + Node { + name: "cpu@1", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "device_type", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 4, + }, + Prop { + name: "status", + data_len: 8, + }, + Prop { + name: "compatible", + data_len: 8, + }, + Prop { + name: "riscv,cboz-block-size", + data_len: 4, + }, + Prop { + name: "riscv,cbom-block-size", + data_len: 4, + }, + Prop { + name: "riscv,isa", + data_len: 124, + }, + Prop { + name: "mmu-type", + data_len: 12, + }, + ], + children: [ + Node { + name: "interrupt-controller", + props: [ + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + Prop { + name: "interrupt-controller", + data_len: 0, + }, + Prop { + name: "compatible", + data_len: 16, + }, + Prop { + name: "phandle", + data_len: 4, + }, + ], + children: [], + }, + ], + }, + Node { + name: "cpu@2", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "device_type", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 4, + }, + Prop { + name: "status", + data_len: 8, + }, + Prop { + name: "compatible", + data_len: 8, + }, + Prop { + name: "riscv,cboz-block-size", + data_len: 4, + }, + Prop { + name: "riscv,cbom-block-size", + data_len: 4, + }, + Prop { + name: "riscv,isa", + data_len: 124, + }, + Prop { + name: "mmu-type", + data_len: 12, + }, + ], + children: [ + Node { + name: "interrupt-controller", + props: [ + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + Prop { + name: "interrupt-controller", + data_len: 0, + }, + Prop { + name: "compatible", + data_len: 16, + }, + Prop { + name: "phandle", + data_len: 4, + }, + ], + children: [], + }, + ], + }, + Node { + name: "cpu@3", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "device_type", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 4, + }, + Prop { + name: "status", + data_len: 8, + }, + Prop { + name: "compatible", + data_len: 8, + }, + Prop { + name: "riscv,cboz-block-size", + data_len: 4, + }, + Prop { + name: "riscv,cbom-block-size", + data_len: 4, + }, + Prop { + name: "riscv,isa", + data_len: 124, + }, + Prop { + name: "mmu-type", + data_len: 12, + }, + ], + children: [ + Node { + name: "interrupt-controller", + props: [ + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + Prop { + name: "interrupt-controller", + data_len: 0, + }, + Prop { + name: "compatible", + data_len: 16, + }, + Prop { + name: "phandle", + data_len: 4, + }, + ], + children: [], + }, + ], + }, + Node { + name: "cpu-map", + props: [], + children: [ + Node { + name: "cluster0", + props: [], + children: [ + Node { + name: "core0", + props: [ + Prop { + name: "cpu", + data_len: 4, + }, + ], + children: [], + }, + Node { + name: "core1", + props: [ + Prop { + name: "cpu", + data_len: 4, + }, + ], + children: [], + }, + Node { + name: "core2", + props: [ + Prop { + name: "cpu", + data_len: 4, + }, + ], + children: [], + }, + Node { + name: "core3", + props: [ + Prop { + name: "cpu", + data_len: 4, + }, + ], + children: [], + }, + ], + }, + ], + }, + ], + }, + Node { + name: "pmu", + props: [ + Prop { + name: "riscv,event-to-mhpmcounters", + data_len: 60, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "fw-cfg@10100000", + props: [ + Prop { + name: "dma-coherent", + data_len: 0, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 20, + }, + ], + children: [], + }, + Node { + name: "flash@20000000", + props: [ + Prop { + name: "bank-width", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 32, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "chosen", + props: [ + Prop { + name: "stdout-path", + data_len: 24, + }, + Prop { + name: "rng-seed", + data_len: 32, + }, + ], + children: [], + }, + Node { + name: "soc", + props: [ + Prop { + name: "#address-cells", + data_len: 4, + }, + Prop { + name: "#size-cells", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 12, + }, + Prop { + name: "ranges", + data_len: 0, + }, + ], + children: [ + Node { + name: "rtc@101000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 20, + }, + ], + children: [], + }, + Node { + name: "serial@10000000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "clock-frequency", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "test@100000", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 36, + }, + ], + children: [], + }, + Node { + name: "pci@30000000", + props: [ + Prop { + name: "interrupt-map-mask", + data_len: 16, + }, + Prop { + name: "interrupt-map", + data_len: 384, + }, + Prop { + name: "ranges", + data_len: 84, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "dma-coherent", + data_len: 0, + }, + Prop { + name: "bus-range", + data_len: 8, + }, + Prop { + name: "linux,pci-domain", + data_len: 4, + }, + Prop { + name: "device_type", + data_len: 4, + }, + Prop { + name: "compatible", + data_len: 24, + }, + Prop { + name: "#size-cells", + data_len: 4, + }, + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + Prop { + name: "#address-cells", + data_len: 4, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10008000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10007000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10006000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10005000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10004000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10003000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10002000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "virtio_mmio@10001000", + props: [ + Prop { + name: "interrupts", + data_len: 4, + }, + Prop { + name: "interrupt-parent", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 12, + }, + ], + children: [], + }, + Node { + name: "plic@c000000", + props: [ + Prop { + name: "phandle", + data_len: 4, + }, + Prop { + name: "riscv,ndev", + data_len: 4, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "interrupts-extended", + data_len: 64, + }, + Prop { + name: "interrupt-controller", + data_len: 0, + }, + Prop { + name: "compatible", + data_len: 32, + }, + Prop { + name: "#address-cells", + data_len: 4, + }, + Prop { + name: "#interrupt-cells", + data_len: 4, + }, + ], + children: [], + }, + Node { + name: "clint@2000000", + props: [ + Prop { + name: "interrupts-extended", + data_len: 64, + }, + Prop { + name: "reg", + data_len: 16, + }, + Prop { + name: "compatible", + data_len: 28, + }, + ], + children: [], + }, + ], + }, + ], +} diff --git a/kernel/test.raw b/kernel/test.raw index 4fce05a4e4ed8cefef2d99f32c519b2fd7841b74..36406a1eee032e80a284d3ed9f5176bba67be064 100644 GIT binary patch delta 4546 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 N{sjXH1{Mq|{s%T@d{qDd delta 61080 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