updated + alignment does not exist
This commit is contained in:
@@ -8,7 +8,7 @@ rustflags = [
|
|||||||
"-C", "link-arg=-Tsrc/arch/riscv64/link.ld",
|
"-C", "link-arg=-Tsrc/arch/riscv64/link.ld",
|
||||||
"-C", "link-arg=--omagic",
|
"-C", "link-arg=--omagic",
|
||||||
]
|
]
|
||||||
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"
|
runner = "qemu-system-riscv64 -nographic -semihosting -cpu rv64 -machine virt -bios none -smp 4 -m 1G -device virtio-blk-pci,drive=mewhen -drive file=test.raw,format=raw,id=mewhen -kernel"
|
||||||
|
|
||||||
[unstable]
|
[unstable]
|
||||||
build-std = ["core", "compiler_builtins", "alloc"]
|
build-std = ["core", "compiler_builtins", "alloc"]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use core::{arch::asm, ops::Range};
|
use core::{arch::naked_asm, ops::Range};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{asm, csr, interrupts, paging, wait},
|
arch::{asm, csr, interrupts, paging, wait},
|
||||||
@@ -8,9 +8,9 @@ use crate::{
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".text.init"]
|
#[link_section = ".text.init"]
|
||||||
#[naked]
|
#[unsafe(naked)]
|
||||||
unsafe extern "C" fn _start() -> ! {
|
unsafe extern "C" fn _start() {
|
||||||
asm!(
|
naked_asm!(
|
||||||
// disable interrupts
|
// disable interrupts
|
||||||
"csrw mie, zero",
|
"csrw mie, zero",
|
||||||
// set up gp & sp
|
// set up gp & sp
|
||||||
@@ -31,15 +31,13 @@ unsafe extern "C" fn _start() -> ! {
|
|||||||
"la t0, {init}",
|
"la t0, {init}",
|
||||||
"csrw mepc, t0",
|
"csrw mepc, t0",
|
||||||
"mret",
|
"mret",
|
||||||
|
|
||||||
init = sym init,
|
init = sym init,
|
||||||
options(noreturn)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
#[unsafe(naked)]
|
||||||
pub unsafe extern "C" fn to_supervisor() {
|
pub unsafe extern "C" fn to_supervisor() {
|
||||||
asm!(
|
naked_asm!(
|
||||||
"li t0, (1 << 8) | (1 << 5)",
|
"li t0, (1 << 8) | (1 << 5)",
|
||||||
"csrw sstatus, t0",
|
"csrw sstatus, t0",
|
||||||
"li t0, (7 << 0) | (1 << 3)",
|
"li t0, (7 << 0) | (1 << 3)",
|
||||||
@@ -53,7 +51,6 @@ pub unsafe extern "C" fn to_supervisor() {
|
|||||||
"csrw sepc, t0",
|
"csrw sepc, t0",
|
||||||
"sfence.vma",
|
"sfence.vma",
|
||||||
"sret",
|
"sret",
|
||||||
options(noreturn)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +61,7 @@ pub unsafe fn init() -> ! {
|
|||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
interrupts::init();
|
interrupts::init();
|
||||||
let fdt = FDT::from_addr(dt_addr);
|
let fdt = FDT::from_addr(dt_addr).expect("Failed to parse fdt");
|
||||||
let raw_mem_range = fdt.mem_range().expect("we lost guys");
|
let raw_mem_range = fdt.mem_range().expect("we lost guys");
|
||||||
let heap_start = paging::init(raw_mem_range.end());
|
let heap_start = paging::init(raw_mem_range.end());
|
||||||
let heap_mem = Range {
|
let heap_mem = Range {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ pub fn init() {
|
|||||||
csr::mtvec::init!(stuff);
|
csr::mtvec::init!(stuff);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(align(4))]
|
#[rustc_align(4)]
|
||||||
pub fn stuff() -> ! {
|
pub fn stuff() -> ! {
|
||||||
let mcause = csr::mcause::read();
|
let mcause = csr::mcause::read();
|
||||||
crate::println!("interrupt triggered: {mcause:?}");
|
crate::println!("interrupt triggered: {mcause:?}");
|
||||||
|
|||||||
@@ -1,35 +1,5 @@
|
|||||||
use core::fmt::{self, Write};
|
|
||||||
|
|
||||||
use crate::util::mutex::Mutex;
|
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
|
|
||||||
// --machine sifive_u
|
|
||||||
// const UART_BASE: u32 = 0x10010000;
|
|
||||||
// --machine virt
|
|
||||||
const UART_BASE: u32 = 0x10000000;
|
|
||||||
static UART: Mutex<Uart> = Mutex::new(Uart::new(UART_BASE));
|
|
||||||
|
|
||||||
struct Uart {
|
|
||||||
base: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Uart {
|
|
||||||
pub const fn new(base: u32) -> Self {
|
|
||||||
Self { base }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Write for Uart {
|
|
||||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
||||||
for b in s.as_bytes() {
|
|
||||||
#[allow(clippy::while_immutable_condition)]
|
|
||||||
while unsafe { *(self.base as *mut i32) } < 0 {}
|
|
||||||
unsafe { *(self.base as *mut i32) = *b as i32 }
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit(code: usize) -> ! {
|
pub fn exit(code: usize) -> ! {
|
||||||
let data = [0x20026, code];
|
let data = [0x20026, code];
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -53,14 +23,3 @@ unsafe fn semihost(call: usize, data: *const u8) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _print(args: core::fmt::Arguments<'_>) {
|
|
||||||
// NOTE: something really dumb can happen here;
|
|
||||||
// if you evaluate an expression in a print statement, and that
|
|
||||||
// causes an interrupt, this will be left locked...
|
|
||||||
// Should I set up the heap before interrupts? or just avoid printing until both...?
|
|
||||||
// or maybe force unlock if there's an interrupt?
|
|
||||||
// or store the hart in the lock, and unlock if that hart was interrupted??
|
|
||||||
// or just have a constant-sized buffer?
|
|
||||||
// or create a "locked writer"?
|
|
||||||
UART.lock().write_fmt(args).unwrap();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -58,31 +58,28 @@ pub struct RawProp {
|
|||||||
|
|
||||||
pub struct FDT {
|
pub struct FDT {
|
||||||
pub header: &'static Header,
|
pub header: &'static Header,
|
||||||
pub nodes: &'static [u8],
|
pub root: Node,
|
||||||
pub strings: &'static [u8],
|
pub strings: &'static [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FDT {
|
impl FDT {
|
||||||
pub fn nodes(&self) -> NodeIter {
|
pub unsafe fn from_addr(addr: *mut u8) -> Result<Self, &'static str> {
|
||||||
NodeIter {
|
|
||||||
pos: self.nodes,
|
|
||||||
strings: self.strings,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn root(&self) -> Option<Node> {
|
|
||||||
self.nodes().next()
|
|
||||||
}
|
|
||||||
pub unsafe fn from_addr(addr: *mut u8) -> Self {
|
|
||||||
let header: &Header = &*(addr as *const Header);
|
let header: &Header = &*(addr as *const Header);
|
||||||
if header.magic.get() != MAGIC {
|
if header.magic.get() != MAGIC {
|
||||||
panic!("fdt magic wrong");
|
return Err("fdt magic wrong");
|
||||||
}
|
}
|
||||||
let data = slice::from_raw_parts(addr, header.totalsize.get() as usize);
|
let data = slice::from_raw_parts(addr, header.totalsize.get() as usize);
|
||||||
Self {
|
let strings = &data[header.off_dt_strings.get() as usize..];
|
||||||
|
let node_data = &data[header.off_dt_struct.get() as usize..];
|
||||||
|
let root = match Node::from_bytes(node_data, strings) {
|
||||||
|
Some((node, _)) => node,
|
||||||
|
None => return Err("Could not parse nodes")
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
header,
|
header,
|
||||||
nodes: &data[header.off_dt_struct.get() as usize..],
|
root,
|
||||||
strings: &data[header.off_dt_strings.get() as usize..],
|
strings,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +104,82 @@ impl Debug for Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
|
pub fn from_bytes(bytes: &'static [u8], strings: &'static [u8]) -> Option<(Self, &'static [u8])> {
|
||||||
|
// first make sure this is actually a node
|
||||||
|
let mut pos = bytes;
|
||||||
|
if pos.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let token: Token = Token::from_bytes(pos)?;
|
||||||
|
let Token::BeginNode = token else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
pos = &pos[4..];
|
||||||
|
// then get the name
|
||||||
|
let name_start = pos;
|
||||||
|
let extra;
|
||||||
|
'outer: loop {
|
||||||
|
let bytes = &pos[..4];
|
||||||
|
pos = &pos[4..];
|
||||||
|
for (i, byte) in bytes.iter().enumerate() {
|
||||||
|
if *byte == 0 {
|
||||||
|
extra = 4 - i;
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let name = core::str::from_utf8(&name_start[..name_start.len() - pos.len() - extra])
|
||||||
|
.expect("har har har har har har har har har har. RAAAAAAAAAAAAAAAAAAAAAAAA");
|
||||||
|
// then props
|
||||||
|
let node_start = pos;
|
||||||
|
let node_data = if let Some(prop) = (PropIter {
|
||||||
|
strings,
|
||||||
|
pos,
|
||||||
|
})
|
||||||
|
.last()
|
||||||
|
{
|
||||||
|
let node_len =
|
||||||
|
(prop.data.as_ptr() as usize + prop.data.len()) - pos.as_ptr() as usize;
|
||||||
|
pos = &pos[node_len..];
|
||||||
|
&node_start[..node_len]
|
||||||
|
} else {
|
||||||
|
&[]
|
||||||
|
};
|
||||||
|
// then children
|
||||||
|
let children = match Token::from_bytes(pos) {
|
||||||
|
Some(Token::EndNode | Token::End) => {
|
||||||
|
pos = &pos[4..];
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
Some(Token::BeginNode) => {
|
||||||
|
let children = pos;
|
||||||
|
let mut iter = NodeIter {
|
||||||
|
pos: children,
|
||||||
|
strings,
|
||||||
|
};
|
||||||
|
// skip children pos
|
||||||
|
for _ in iter.by_ref() {}
|
||||||
|
pos = iter.pos;
|
||||||
|
match Token::from_bytes(pos) {
|
||||||
|
Some(Token::EndNode | Token::End) => pos = &pos[4..],
|
||||||
|
_ => panic!("wut du heeeeeal (toaken)"),
|
||||||
|
}
|
||||||
|
children
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("WARNING: token stuff XD");
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// done
|
||||||
|
Some((Node {
|
||||||
|
name,
|
||||||
|
props: node_data,
|
||||||
|
strings,
|
||||||
|
children,
|
||||||
|
},pos))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn children(&self) -> NodeIter {
|
pub fn children(&self) -> NodeIter {
|
||||||
NodeIter {
|
NodeIter {
|
||||||
pos: self.children,
|
pos: self.children,
|
||||||
@@ -191,85 +264,16 @@ impl Iterator for PropIter {
|
|||||||
pub struct NodeIter {
|
pub struct NodeIter {
|
||||||
// I should make a type called ByteCursor or something for this
|
// I should make a type called ByteCursor or something for this
|
||||||
// so dealing with it is not cursed and dependent on data type
|
// so dealing with it is not cursed and dependent on data type
|
||||||
pub pos: &'static [u8],
|
pos: &'static [u8],
|
||||||
pub strings: &'static [u8],
|
strings: &'static [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for NodeIter {
|
impl Iterator for NodeIter {
|
||||||
type Item = Node;
|
type Item = Node;
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
// first make sure this is actually a node
|
let (node, pos) = Node::from_bytes(self.pos, self.strings)?;
|
||||||
if self.pos.is_empty() {
|
self.pos = pos;
|
||||||
return None;
|
Some(node)
|
||||||
}
|
|
||||||
let token: Token = Token::from_bytes(self.pos)?;
|
|
||||||
let Token::BeginNode = token else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
self.pos = &self.pos[4..];
|
|
||||||
// then get the name
|
|
||||||
let name_start = self.pos;
|
|
||||||
let extra;
|
|
||||||
'outer: loop {
|
|
||||||
let bytes = &self.pos[..4];
|
|
||||||
self.pos = &self.pos[4..];
|
|
||||||
for (i, byte) in bytes.iter().enumerate() {
|
|
||||||
if *byte == 0 {
|
|
||||||
extra = 4 - i;
|
|
||||||
break 'outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let name = core::str::from_utf8(&name_start[..name_start.len() - self.pos.len() - extra])
|
|
||||||
.expect("har har har har har har har har har har. RAAAAAAAAAAAAAAAAAAAAAAAA");
|
|
||||||
// then props
|
|
||||||
let node_start = self.pos;
|
|
||||||
let node_data = if let Some(prop) = (PropIter {
|
|
||||||
strings: self.strings,
|
|
||||||
pos: self.pos,
|
|
||||||
})
|
|
||||||
.last()
|
|
||||||
{
|
|
||||||
let node_len =
|
|
||||||
(prop.data.as_ptr() as usize + prop.data.len()) - self.pos.as_ptr() as usize;
|
|
||||||
self.pos = &self.pos[node_len..];
|
|
||||||
&node_start[..node_len]
|
|
||||||
} else {
|
|
||||||
&[]
|
|
||||||
};
|
|
||||||
// then children
|
|
||||||
let children = match Token::from_bytes(self.pos) {
|
|
||||||
Some(Token::EndNode | Token::End) => {
|
|
||||||
self.pos = &self.pos[4..];
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
Some(Token::BeginNode) => {
|
|
||||||
let children = self.pos;
|
|
||||||
let mut iter = Self {
|
|
||||||
pos: children,
|
|
||||||
strings: self.strings,
|
|
||||||
};
|
|
||||||
// skip children bytes
|
|
||||||
for _ in iter.by_ref() {}
|
|
||||||
self.pos = iter.pos;
|
|
||||||
match Token::from_bytes(self.pos) {
|
|
||||||
Some(Token::EndNode | Token::End) => self.pos = &self.pos[4..],
|
|
||||||
_ => panic!("wut du heeeeeal (toaken)"),
|
|
||||||
}
|
|
||||||
children
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
println!("WARNING: token stuff XD");
|
|
||||||
&[]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// done
|
|
||||||
Some(Node {
|
|
||||||
name,
|
|
||||||
props: node_data,
|
|
||||||
strings: self.strings,
|
|
||||||
children,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ use super::fdt::FDT;
|
|||||||
|
|
||||||
impl FDT {
|
impl FDT {
|
||||||
pub fn mem_range(&self) -> Option<FDTMemRange> {
|
pub fn mem_range(&self) -> Option<FDTMemRange> {
|
||||||
let reg = self.root()?.child("memory")?.prop("reg")?;
|
let reg = self.root.child("memory")?.prop("reg")?;
|
||||||
let data = reg.data.chunks(size_of::<FDTMemRange>()).next()?;
|
let data = reg.data.chunks(size_of::<FDTMemRange>()).next()?;
|
||||||
|
// for now just get first
|
||||||
let data: [u8; size_of::<FDTMemRange>()] = data.try_into().unwrap();
|
let data: [u8; size_of::<FDTMemRange>()] = data.try_into().unwrap();
|
||||||
unsafe { Some(transmute::<[u8; 16], FDTMemRange>(data)) }
|
unsafe { Some(transmute::<[u8; 16], FDTMemRange>(data)) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod fdt;
|
pub mod fdt;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod uart;
|
|
||||||
pub mod pci;
|
pub mod pci;
|
||||||
|
pub mod uart;
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
use crate::println;
|
|
||||||
|
|
||||||
use super::fdt::FDT;
|
|
||||||
|
|
||||||
impl FDT {
|
|
||||||
pub fn pci_devs(&self) -> Option<()> {
|
|
||||||
// for dev in self.nodes() {
|
|
||||||
// println!("{:#?}", dev);
|
|
||||||
// }
|
|
||||||
let node = self.root()?.child("soc")?.child("pci")?;
|
|
||||||
println!("{:#?}", node);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
98
kernel/src/dev/pci/class.rs
Normal file
98
kernel/src/dev/pci/class.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use super::header::HeaderStart;
|
||||||
|
|
||||||
|
// this is technically less performant than making 16^2 values,
|
||||||
|
// but that cannot be worth it lmao +
|
||||||
|
// Reserved(u8) is a lot nicer than literally hundreds of enum values
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Class {
|
||||||
|
Unclassified,
|
||||||
|
MassStorageController,
|
||||||
|
NetworkController,
|
||||||
|
DisplayController,
|
||||||
|
MultimediaController,
|
||||||
|
MemoryController,
|
||||||
|
Bridge(Bridge),
|
||||||
|
SimpleCommunicationController,
|
||||||
|
BaseSystemPeripheral,
|
||||||
|
InputDeviceController,
|
||||||
|
DockingStation,
|
||||||
|
Processor,
|
||||||
|
SerialBusController,
|
||||||
|
WirelessController,
|
||||||
|
IntelligentController,
|
||||||
|
SatelliteCommunicationController,
|
||||||
|
EncryptionController,
|
||||||
|
SignalProcessingController,
|
||||||
|
ProcessingAccelerator,
|
||||||
|
NonEssentialInstrumentation,
|
||||||
|
CoProcessor,
|
||||||
|
UnassignedClass,
|
||||||
|
Reserved(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Class {
|
||||||
|
pub fn from_header(header: &HeaderStart) -> Self {
|
||||||
|
match header.class_code {
|
||||||
|
0x0 => Self::Unclassified,
|
||||||
|
0x1 => Self::MassStorageController,
|
||||||
|
0x2 => Self::NetworkController,
|
||||||
|
0x3 => Self::DisplayController,
|
||||||
|
0x4 => Self::MultimediaController,
|
||||||
|
0x5 => Self::MemoryController,
|
||||||
|
0x6 => Self::Bridge(Bridge::from_header(header)),
|
||||||
|
0x7 => Self::SimpleCommunicationController,
|
||||||
|
0x8 => Self::BaseSystemPeripheral,
|
||||||
|
0x9 => Self::InputDeviceController,
|
||||||
|
0xa => Self::DockingStation,
|
||||||
|
0xb => Self::Processor,
|
||||||
|
0xc => Self::SerialBusController,
|
||||||
|
0xd => Self::WirelessController,
|
||||||
|
0xe => Self::IntelligentController,
|
||||||
|
0xf => Self::SatelliteCommunicationController,
|
||||||
|
0x10 => Self::EncryptionController,
|
||||||
|
0x11 => Self::SignalProcessingController,
|
||||||
|
0x12 => Self::ProcessingAccelerator,
|
||||||
|
0x13 => Self::NonEssentialInstrumentation,
|
||||||
|
0x40 => Self::CoProcessor,
|
||||||
|
0xff => Self::UnassignedClass,
|
||||||
|
c => Self::Reserved(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Bridge {
|
||||||
|
Host,
|
||||||
|
ISA,
|
||||||
|
EISA,
|
||||||
|
MCA,
|
||||||
|
PCIToPCI,
|
||||||
|
PCMCIA,
|
||||||
|
NuBus,
|
||||||
|
CardBus,
|
||||||
|
RACEway,
|
||||||
|
PCIToPCISemiTransparent,
|
||||||
|
InfiniBandtoPCIHost,
|
||||||
|
Other,
|
||||||
|
Unknown(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bridge {
|
||||||
|
pub fn from_header(header: &HeaderStart) -> Self {
|
||||||
|
match header.subclass {
|
||||||
|
0x0 => Self::Host,
|
||||||
|
0x1 => Self::ISA,
|
||||||
|
0x2 => Self::EISA,
|
||||||
|
0x3 => Self::MCA,
|
||||||
|
0x4 => Self::PCIToPCI,
|
||||||
|
0x5 => Self::PCMCIA,
|
||||||
|
0x6 => Self::NuBus,
|
||||||
|
0x7 => Self::CardBus,
|
||||||
|
0x8 => Self::RACEway,
|
||||||
|
0x9 => Self::PCIToPCISemiTransparent,
|
||||||
|
0x0A => Self::InfiniBandtoPCIHost,
|
||||||
|
0x80 => Self::Other,
|
||||||
|
s => Self::Unknown(s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
kernel/src/dev/pci/header.rs
Normal file
84
kernel/src/dev/pci/header.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use super::class::Class;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct HeaderStart {
|
||||||
|
pub vendor_id: u16,
|
||||||
|
pub device_id: u16,
|
||||||
|
pub command: u16,
|
||||||
|
pub status: u16,
|
||||||
|
pub rev_id: u8,
|
||||||
|
pub prog_if: u8,
|
||||||
|
pub subclass: u8,
|
||||||
|
pub class_code: u8,
|
||||||
|
pub cache_line_size: u8,
|
||||||
|
pub latency_timer: u8,
|
||||||
|
pub header_type: u8,
|
||||||
|
pub bist: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeaderStart {
|
||||||
|
pub fn class(&self) -> Class {
|
||||||
|
Class::from_header(self)
|
||||||
|
}
|
||||||
|
pub fn vendor(&self) -> Vendor {
|
||||||
|
Vendor::from_header(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct GeneralHeader {
|
||||||
|
pub start: HeaderStart,
|
||||||
|
pub bar0: u32,
|
||||||
|
pub bar1: u32,
|
||||||
|
pub bar2: u32,
|
||||||
|
pub bar3: u32,
|
||||||
|
pub bar4: u32,
|
||||||
|
pub bar5: u32,
|
||||||
|
pub cardbus_cis_pointer: u32,
|
||||||
|
pub subsystem_vendor_id: u16,
|
||||||
|
pub subsystem_id: u16,
|
||||||
|
pub expansion_rom_base_addr: u32,
|
||||||
|
pub capabilities: u8,
|
||||||
|
pub reserved: [u8; 7],
|
||||||
|
pub interrupt_line: u8,
|
||||||
|
pub interrupt_pin: u8,
|
||||||
|
pub min_grant: u8,
|
||||||
|
pub max_latency: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// due to how large this is and how it can change,
|
||||||
|
// this seems like not the best use case for enums
|
||||||
|
// but that's entirely a later problem
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Vendor {
|
||||||
|
RedHat(RedHatDevice),
|
||||||
|
Unknown(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vendor {
|
||||||
|
pub fn from_header(header: &HeaderStart) -> Self {
|
||||||
|
let id = header.device_id;
|
||||||
|
match header.vendor_id {
|
||||||
|
0x1b36 => Self::RedHat(RedHatDevice::from_id(id)),
|
||||||
|
i => Self::Unknown(i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RedHatDevice {
|
||||||
|
QemuPCIeHostBridge,
|
||||||
|
Unknown(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RedHatDevice {
|
||||||
|
pub fn from_id(id: u16) -> Self {
|
||||||
|
match id {
|
||||||
|
0x0008 => Self::QemuPCIeHostBridge,
|
||||||
|
id => Self::Unknown(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
45
kernel/src/dev/pci/mod.rs
Normal file
45
kernel/src/dev/pci/mod.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
use super::fdt::FDT;
|
||||||
|
use crate::{dev::pci::header::{GeneralHeader, HeaderStart}, println, util::bits::Be};
|
||||||
|
use core::mem::transmute;
|
||||||
|
|
||||||
|
pub mod header;
|
||||||
|
pub mod class;
|
||||||
|
|
||||||
|
impl FDT {
|
||||||
|
pub fn pci_devs(&self) -> Option<()> {
|
||||||
|
// for dev in self.nodes() {
|
||||||
|
// println!("{:#?}", dev);
|
||||||
|
// }
|
||||||
|
let node = self.root.child("soc")?.child("pci")?;
|
||||||
|
// should make handling reg field nicer
|
||||||
|
let data = node.prop("reg")?.data;
|
||||||
|
println!("{:#?}", node);
|
||||||
|
let addr = unsafe {
|
||||||
|
transmute::<[u8; 8], Be<u64>>([
|
||||||
|
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
|
||||||
|
])
|
||||||
|
};
|
||||||
|
let addr = addr.get() as *mut u8;
|
||||||
|
let len = unsafe {
|
||||||
|
transmute::<[u8; 8], Be<u64>>([
|
||||||
|
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
|
||||||
|
])
|
||||||
|
};
|
||||||
|
let len = len.get() as usize;
|
||||||
|
println!("{:?}..{:?}", addr, unsafe { addr.byte_add(len) });
|
||||||
|
unsafe {
|
||||||
|
let header = *(addr as *mut HeaderStart);
|
||||||
|
if header.header_type != 0 {
|
||||||
|
panic!("nooooooooooooo");
|
||||||
|
}
|
||||||
|
let header = addr as *mut GeneralHeader;
|
||||||
|
println!("device: {:?}", (*header).start.vendor());
|
||||||
|
println!("class: {:?}", (*header).start.class());
|
||||||
|
println!("{:#?}", *header);
|
||||||
|
(*header).start.command = 0b0000_0000_0000_0110;
|
||||||
|
for _ in 0..1000000 {}
|
||||||
|
println!("{:b}", (*header).start.status);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
pub struct Uart {
|
||||||
|
base: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Uart {
|
||||||
|
pub const fn new(base: u32) -> Self {
|
||||||
|
Self { base }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Write for Uart {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
for b in s.as_bytes() {
|
||||||
|
#[allow(clippy::while_immutable_condition)]
|
||||||
|
while unsafe { *(self.base as *mut i32) } < 0 {}
|
||||||
|
unsafe { *(self.base as *mut i32) = *b as i32 }
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
40
kernel/src/log.rs
Normal file
40
kernel/src/log.rs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use crate::{dev::{fdt::FDT, uart::Uart}, util::mutex::Mutex};
|
||||||
|
|
||||||
|
// ok now it uses soc->serial, might be chillin?
|
||||||
|
// --machine sifive_u
|
||||||
|
// const UART_BASE: u32 = 0x10010000;
|
||||||
|
// --machine virt
|
||||||
|
const UART_BASE: u32 = 0x10000000;
|
||||||
|
static UART: Mutex<Uart> = Mutex::new(Uart::new(UART_BASE));
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::log::_print(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => ($crate::print!("\n"));
|
||||||
|
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(dt: &FDT) -> Option<()> {
|
||||||
|
let node = dt.root.child("soc")?.child("serial")?;
|
||||||
|
let addr = u32::from_str_radix(node.address()?, 16).ok()?;
|
||||||
|
*UART.lock() = Uart::new(addr);
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _print(args: core::fmt::Arguments<'_>) {
|
||||||
|
// NOTE: something really dumb can happen here;
|
||||||
|
// if you evaluate an expression in a print statement, and that
|
||||||
|
// causes an interrupt, this will be left locked...
|
||||||
|
// Should I set up the heap before interrupts? or just avoid printing until both...?
|
||||||
|
// or maybe force unlock if there's an interrupt?
|
||||||
|
// or store the hart in the lock, and unlock if that hart was interrupted??
|
||||||
|
// or just have a constant-sized buffer?
|
||||||
|
// or create a "locked writer"?
|
||||||
|
UART.lock().write_fmt(args).unwrap();
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
#![feature(naked_functions)]
|
|
||||||
#![feature(fn_align)]
|
#![feature(fn_align)]
|
||||||
#![feature(custom_test_frameworks)]
|
#![feature(custom_test_frameworks)]
|
||||||
#![test_runner(crate::test::test_runner)]
|
#![test_runner(crate::test::test_runner)]
|
||||||
@@ -15,6 +14,7 @@ extern crate alloc;
|
|||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
pub mod dev;
|
pub mod dev;
|
||||||
|
pub mod log;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod qemu;
|
pub mod qemu;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -23,7 +23,7 @@ pub mod util;
|
|||||||
|
|
||||||
pub struct StartInfo {
|
pub struct StartInfo {
|
||||||
mem_range: Range<*mut u8>,
|
mem_range: Range<*mut u8>,
|
||||||
dt: FDT
|
dt: FDT,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(info: StartInfo) -> ! {
|
pub fn start(info: StartInfo) -> ! {
|
||||||
@@ -39,12 +39,18 @@ pub fn start(info: StartInfo) -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn main(info: StartInfo) {
|
pub fn main(info: StartInfo) {
|
||||||
|
log::init(&info.dt);
|
||||||
println!("we out here vibin");
|
println!("we out here vibin");
|
||||||
println!("memory range: {:?}", info.mem_range);
|
// println!("memory range: {:?}", info.mem_range);
|
||||||
unsafe {
|
unsafe {
|
||||||
ALLOCATOR.init(&info.mem_range);
|
ALLOCATOR.init(&info.mem_range);
|
||||||
}
|
}
|
||||||
info.dt.pci_devs();
|
// info.dt.pci_devs();
|
||||||
|
// println!("{:#?}", info.dt.root);
|
||||||
|
let test = alloc::vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||||
|
let test2 = alloc::vec![1u8, 2, 3, 4];
|
||||||
|
drop(test);
|
||||||
|
ALLOCATOR.heap().print();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ impl Heap {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null_mut();
|
null_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn dealloc(&mut self, ptr: *mut u8, _: core::alloc::Layout) {
|
pub unsafe fn dealloc(&mut self, ptr: *mut u8, _: core::alloc::Layout) {
|
||||||
|
|||||||
@@ -1,12 +1 @@
|
|||||||
pub use crate::arch::qemu::*;
|
pub use crate::arch::qemu::*;
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => ($crate::arch::qemu::_print(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! println {
|
|
||||||
() => ($crate::print!("\n"));
|
|
||||||
($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ pub fn run_tests() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(info: &StartInfo) {
|
fn prepare(info: &StartInfo) {
|
||||||
|
crate::log::init(&info.dt);
|
||||||
unsafe {
|
unsafe {
|
||||||
ALLOCATOR.reset(&info.mem_range);
|
ALLOCATOR.reset(&info.mem_range);
|
||||||
}
|
}
|
||||||
|
|||||||
1128
kernel/stuff
1128
kernel/stuff
File diff suppressed because it is too large
Load Diff
977
runner/Cargo.lock
generated
977
runner/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user