x86-64: sync x86-64 up with the new kernel structure

This commit is contained in:
Mark Poliakov 2023-08-21 17:26:44 +03:00
parent b0379e398f
commit af5529a84f
57 changed files with 1357 additions and 1315 deletions

View File

@ -11,6 +11,7 @@ yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
vfs = { path = "lib/vfs" }
memfs = { path = "lib/memfs" }
device-api = { path = "lib/device-api", features = ["derive"] }
kernel-util = { path = "lib/kernel-util" }
atomic_enum = "0.2.0"
bitflags = "2.3.3"
@ -21,12 +22,10 @@ tock-registers = "0.8.1"
cfg-if = "1.0.0"
git-version = "0.3.5"
aarch64-cpu = "9.3.1"
bitmap-font = { version = "0.3.0", optional = true }
embedded-graphics = { version = "0.8.0", optional = true }
fdt-rs = { version = "0.4.3", default-features = false }
log = "0.4.20"
[dependencies.elf]
version = "0.7.2"
@ -35,6 +34,8 @@ default-features = false
features = ["no_std_stream"]
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64-cpu = "9.3.1"
fdt-rs = { version = "0.4.3", default-features = false }
[target.'cfg(target_arch = "x86_64")'.dependencies]
yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }

View File

@ -0,0 +1,11 @@
use yggdrasil_abi::error::Error;
use crate::Device;
pub trait KeyboardConsumer {
fn handle_character(&self, data: u8) -> Result<(), Error>;
}
pub trait KeyboardProducer: Device {
fn connect(&self, to: &'static dyn KeyboardConsumer);
}

View File

@ -27,11 +27,11 @@ pub enum IpiDeliveryTarget {
OtherCpus,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum IrqNumber {
Private(u32),
Shared(u32),
}
// #[derive(Clone, Copy, PartialEq, Eq, Debug)]
// pub enum IrqNumber {
// Private(u32),
// Shared(u32),
// }
#[derive(Default, Clone, Copy, Debug)]
pub struct IrqOptions {
@ -44,17 +44,19 @@ pub trait InterruptTable {
}
pub trait ExternalInterruptController {
type IrqNumber;
/// Performs IRQ delivery method configuration and registers a handler to execute when it is
/// fired
fn register_irq(
&self,
irq: IrqNumber,
irq: Self::IrqNumber,
options: IrqOptions,
handler: &'static dyn InterruptHandler,
) -> Result<(), Error>;
/// Enables the specified IRQ (unmasks it)
fn enable_irq(&self, irq: IrqNumber) -> Result<(), Error>;
fn enable_irq(&self, irq: Self::IrqNumber) -> Result<(), Error>;
/// Handles a single pending interrupt on this controller.
/// The function is intended for interrupt controllers which have internal registers to track
@ -107,6 +109,15 @@ impl<const SIZE: usize> FixedInterruptTable<SIZE> {
self.entries[index] = Some(handler);
Ok(())
}
pub fn insert_least_loaded(
&mut self,
handler: &'static dyn InterruptHandler,
) -> Result<usize, Error> {
let index = self.entries.iter().position(|p| p.is_none()).unwrap();
self.entries[index].replace(handler);
Ok(index)
}
}
impl<const SIZE: usize> InterruptTable for FixedInterruptTable<SIZE> {

View File

@ -4,6 +4,7 @@ extern crate alloc;
pub mod bus;
pub mod device;
pub mod input;
pub mod interrupt;
pub mod manager;
pub mod serial;
@ -24,5 +25,11 @@ pub trait CpuBringupDevice: Device {
}
pub trait ResetDevice: Device {
/// Performs a system reset.
///
/// # Safety
///
/// The kernel must ensure it is actually safe to perform a reset, no critical operations
/// are aborted and no data is lost.
unsafe fn reset(&self) -> !;
}

View File

@ -0,0 +1,8 @@
[package]
name = "kernel-util"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,5 @@
#![no_std]
#![feature(maybe_uninit_slice)]
pub mod sync;
pub mod util;

View File

View File

@ -1,4 +1,4 @@
use core::marker::PhantomData;
use core::{cell::RefCell, marker::PhantomData};
use alloc::boxed::Box;
@ -15,12 +15,12 @@ pub(crate) struct DirectoryNode<A: BlockAllocator> {
}
impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
fn create(&self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
let child = Vnode::new(name, kind);
match kind {
VnodeKind::Directory => child.set_data(Box::new(Self { _pd: PhantomData })),
VnodeKind::Regular => child.set_data(Box::new(FileNode {
data: BVec::<A>::new(),
data: RefCell::new(BVec::<A>::new()),
})),
_ => todo!(),
}
@ -28,24 +28,19 @@ impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
Ok(child)
}
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
fn open(&self, _node: &VnodeRef, _opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
Ok(DIR_POSITION_FROM_CACHE)
}
fn remove(&mut self, _at: &VnodeRef, _name: &str) -> Result<(), Error> {
fn remove(&self, _at: &VnodeRef, _name: &str) -> Result<(), Error> {
Ok(())
}
fn size(&mut self, node: &VnodeRef) -> Result<u64, Error> {
fn size(&self, node: &VnodeRef) -> Result<u64, Error> {
Ok(node.children().len() as u64)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
mode: FileMode::default_dir(),

View File

@ -1,3 +1,5 @@
use core::cell::RefCell;
use vfs::{VnodeImpl, VnodeRef};
use yggdrasil_abi::{
error::Error,
@ -7,37 +9,37 @@ use yggdrasil_abi::{
use crate::{block::BlockAllocator, bvec::BVec};
pub(crate) struct FileNode<A: BlockAllocator> {
pub(crate) data: BVec<'static, A>,
pub(crate) data: RefCell<BVec<'static, A>>,
}
impl<A: BlockAllocator> VnodeImpl for FileNode<A> {
fn open(&mut self, _node: &VnodeRef, opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
fn open(&self, _node: &VnodeRef, opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
if opts.contains(OpenOptions::APPEND) {
Ok(self.data.size() as u64)
Ok(self.data.borrow().size() as u64)
} else {
Ok(0)
}
}
fn close(&mut self, _node: &VnodeRef) -> Result<(), Error> {
fn close(&self, _node: &VnodeRef) -> Result<(), Error> {
Ok(())
}
fn read(&mut self, _node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
self.data.read(pos, data)
fn read(&self, _node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
self.data.borrow().read(pos, data)
}
fn write(&mut self, _node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
self.data.write(pos, data)
fn write(&self, _node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
self.data.borrow_mut().write(pos, data)
}
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
Ok(self.data.size() as u64)
fn size(&self, _node: &VnodeRef) -> Result<u64, Error> {
Ok(self.data.borrow().size() as u64)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: self.data.size() as u64,
size: self.data.borrow().size() as u64,
mode: FileMode::default_file(),
ty: FileType::File,
})

View File

@ -162,7 +162,9 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
let bvec = BVec::<A>::try_from(data)?;
assert_eq!(bvec.size(), data.len());
node.set_data(Box::new(FileNode { data: bvec }));
node.set_data(Box::new(FileNode {
data: RefCell::new(bvec),
}));
}
}

View File

@ -7,4 +7,5 @@ edition = "2021"
[dependencies]
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
kernel-util = { path = "../kernel-util" }
bitflags = "2.3.3"

View File

@ -23,28 +23,23 @@ impl CharDeviceWrapper {
}
impl VnodeImpl for CharDeviceWrapper {
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
fn open(&self, _node: &VnodeRef, _opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
Ok(0)
}
fn close(&mut self, _node: &VnodeRef) -> Result<(), Error> {
fn close(&self, _node: &VnodeRef) -> Result<(), Error> {
Ok(())
}
fn read(&mut self, _node: &VnodeRef, _pos: u64, data: &mut [u8]) -> Result<usize, Error> {
fn read(&self, _node: &VnodeRef, _pos: u64, data: &mut [u8]) -> Result<usize, Error> {
self.device.read(true, data)
}
fn write(&mut self, _node: &VnodeRef, _pos: u64, data: &[u8]) -> Result<usize, Error> {
fn write(&self, _node: &VnodeRef, _pos: u64, data: &[u8]) -> Result<usize, Error> {
self.device.write(true, data)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
ty: FileType::Char,
@ -52,7 +47,7 @@ impl VnodeImpl for CharDeviceWrapper {
})
}
fn device_request(&mut self, _node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
fn device_request(&self, _node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
self.device.device_request(req)
}
}

View File

@ -9,6 +9,7 @@ use alloc::{
string::String,
vec::Vec,
};
use kernel_util::util::OneTimeInit;
use yggdrasil_abi::{
error::Error,
io::{DeviceRequest, FileAttr, FileMode, FileType, OpenOptions},
@ -44,46 +45,46 @@ pub struct Vnode {
name: String,
tree: RefCell<TreeNode>,
kind: VnodeKind,
data: RefCell<Option<Box<dyn VnodeImpl>>>,
data: OneTimeInit<Box<dyn VnodeImpl>>,
fs: RefCell<Option<Rc<dyn Filesystem>>>,
target: RefCell<Option<VnodeRef>>,
}
#[allow(unused_variables)]
pub trait VnodeImpl {
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
fn create(&self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
Err(Error::NotImplemented)
}
fn remove(&mut self, at: &VnodeRef, name: &str) -> Result<(), Error> {
fn remove(&self, at: &VnodeRef, name: &str) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn open(&mut self, node: &VnodeRef, opts: OpenOptions, mode: FileMode) -> Result<u64, Error> {
fn open(&self, node: &VnodeRef, opts: OpenOptions, mode: FileMode) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn close(&mut self, node: &VnodeRef) -> Result<(), Error> {
fn close(&self, node: &VnodeRef) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
fn read(&self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn write(&mut self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
fn write(&self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn size(&mut self, node: &VnodeRef) -> Result<u64, Error> {
fn size(&self, node: &VnodeRef) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn metadata(&mut self, node: &VnodeRef) -> Result<FileAttr, Error> {
fn metadata(&self, node: &VnodeRef) -> Result<FileAttr, Error> {
Err(Error::NotImplemented)
}
fn device_request(&mut self, node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
fn device_request(&self, node: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
Err(Error::NotImplemented)
}
}
@ -97,7 +98,7 @@ impl Vnode {
children: Vec::new(),
}),
kind,
data: RefCell::new(None),
data: OneTimeInit::new(),
fs: RefCell::new(None),
target: RefCell::new(None),
})
@ -119,14 +120,18 @@ impl Vnode {
}
#[inline]
pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
match self.data.try_borrow_mut() {
Ok(r) => r,
Err(e) => {
panic!("{:?} on {:?}", e, self.name())
}
}
pub fn data(&self) -> Option<&dyn VnodeImpl> {
self.data.try_get().map(Box::as_ref)
}
// #[inline]
// pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
// match self.data.try_borrow_mut() {
// Ok(r) => r,
// Err(e) => {
// panic!("{:?} on {:?}", e, self.name())
// }
// }
// }
#[inline]
pub fn fs(&self) -> Option<Rc<dyn Filesystem>> {
@ -151,7 +156,8 @@ impl Vnode {
}
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
self.data.borrow_mut().replace(data);
self.data.init(data);
// self.data.borrow_mut().replace(data);
}
pub fn set_fs(&self, data: Rc<dyn Filesystem>) {
@ -273,7 +279,7 @@ impl Vnode {
return Err(Error::IsADirectory);
}
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
let pos = data.open(self, flags, mode)?;
Ok(File::normal(self.clone(), pos, open_flags))
} else {
@ -286,7 +292,7 @@ impl Vnode {
return Err(Error::IsADirectory);
}
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
let pos = data.open(self, OpenOptions::READ, FileMode::empty())?;
Ok(File::directory(self.clone(), pos))
} else {
@ -296,7 +302,7 @@ impl Vnode {
}
pub fn close(self: &VnodeRef) -> Result<(), Error> {
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.close(self)
} else {
Ok(())
@ -317,7 +323,7 @@ impl Vnode {
e => return e,
};
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
let vnode = data.create(self, name, kind)?;
if let Some(fs) = self.fs() {
vnode.set_fs(fs);
@ -350,7 +356,7 @@ impl Vnode {
}
}
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.remove(self, name)?;
}
@ -365,7 +371,7 @@ impl Vnode {
todo!();
}
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.write(self, pos, buf)
} else {
todo!()
@ -377,7 +383,7 @@ impl Vnode {
todo!();
}
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.read(self, pos, buf)
} else {
todo!()
@ -385,7 +391,7 @@ impl Vnode {
}
pub fn size(self: &VnodeRef) -> Result<u64, Error> {
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.size(self)
} else {
todo!();
@ -435,7 +441,7 @@ impl Vnode {
}
pub fn metadata(self: &VnodeRef) -> Result<FileAttr, Error> {
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.metadata(self)
} else {
todo!()
@ -443,7 +449,7 @@ impl Vnode {
}
pub fn device_request(self: &VnodeRef, req: &mut DeviceRequest) -> Result<(), Error> {
if let Some(ref mut data) = *self.data() {
if let Some(data) = self.data() {
data.device_request(self, req)
} else {
todo!()

View File

@ -100,7 +100,6 @@ unsafe extern "C" fn __aarch64_bsp_upper_entry(dtb_phys: usize) -> ! {
Cpu::init_local();
kernel_main()
// kernel_main(dtb_phys)
}
extern "C" fn __aarch64_ap_upper_entry(_x0: usize) -> ! {

View File

@ -3,11 +3,10 @@ use core::sync::atomic::Ordering;
use aarch64_cpu::registers::{MPIDR_EL1, TPIDR_EL1};
use alloc::{boxed::Box, vec::Vec};
use kernel_util::util::OneTimeInit;
use tock_registers::interfaces::{Readable, Writeable};
use crate::{
arch::CpuMessage, panic, sync::IrqSafeSpinlock, task::sched::CpuQueue, util::OneTimeInit,
};
use crate::{arch::CpuMessage, panic, sync::IrqSafeSpinlock, task::sched::CpuQueue};
use super::smp::CPU_COUNT;

View File

@ -1,299 +0,0 @@
//! ARM device tree utlities
use fdt_rs::{
base::DevTree,
index::{iters::DevTreeIndexNodeSiblingIter, DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp},
prelude::PropReader,
};
use crate::{debug::LogLevel, mem::phys::PhysicalMemoryRegion};
const INDEX_BUFFER_SIZE: usize = 65536;
#[repr(C, align(0x10))]
struct FdtIndexBuffer([u8; INDEX_BUFFER_SIZE]);
static mut FDT_INDEX_BUFFER: FdtIndexBuffer = FdtIndexBuffer::zeroed();
impl FdtIndexBuffer {
const fn zeroed() -> Self {
Self([0; INDEX_BUFFER_SIZE])
}
}
/// Device tree node
pub type TNode<'a> = DevTreeIndexNode<'a, 'a, 'a>;
/// Device tree property
pub type TProp<'a> = DevTreeIndexProp<'a, 'a, 'a>;
/// Helper trait to provide extra functionality for [DevTreeIndexProp]
pub trait DevTreeIndexPropExt {
/// Reads a cell value from single-type cell array at given cell index
fn cell1_array_item(&self, index: usize, cells: usize) -> Option<u64>;
/// Reads a cell pair from cell pair array at given pair index
fn cell2_array_item(&self, index: usize, cells0: usize, cells1: usize) -> Option<(u64, u64)>;
/// Reads a cell value from the property at given offset
fn read_cell(&self, u32_offset: usize, cell_size: usize) -> Option<u64>;
}
/// Helper trait to provide extra functionality for [DevTreeIndexNode]
pub trait DevTreeIndexNodeExt {
/// Returns the root node's `#address-cells` property, or the default value defined by the
/// specification if it's absent
fn address_cells(&self) -> usize {
self.get_address_cells().unwrap_or(2)
}
/// Returns the root node's `#size-cells` property, or the default value defined by the
/// specification if it's absent
fn size_cells(&self) -> usize {
self.get_size_cells().unwrap_or(1)
}
/// Returns the #address-cells property of the node, if there is one
fn get_address_cells(&self) -> Option<usize>;
/// Returns the #size-cells property of the node, if there is one
fn get_size_cells(&self) -> Option<usize>;
/// Prints the node contents to debug output
fn dump(&self, level: LogLevel, depth: usize);
}
/// Extension trait for [DevTreeIndexNode] to obtain typed property values
pub trait DevTreeIndexNodePropGet<T> {
/// Returns a property value of given type, if it exists
fn prop(&self, name: &str) -> Option<T>;
}
impl<'a, 'i, 'dt> DevTreeIndexNodePropGet<u32> for DevTreeIndexNode<'a, 'i, 'dt> {
fn prop(&self, name: &str) -> Option<u32> {
self.props().find_map(|prop| {
if prop.name().ok()? == name {
prop.u32(0).ok()
} else {
None
}
})
}
}
impl<'a, 'i, 'dt> DevTreeIndexNodePropGet<&'a str> for DevTreeIndexNode<'a, 'i, 'dt> {
fn prop(&self, name: &str) -> Option<&'a str> {
self.props().find_map(|prop| {
if prop.name().ok()? == name {
prop.str().ok()
} else {
None
}
})
}
}
/// Iterator for physical memory regions present in the device tree
#[derive(Clone)]
pub struct FdtMemoryRegionIter<'a> {
inner: DevTreeIndexNodeSiblingIter<'a, 'a, 'a>,
address_cells: usize,
size_cells: usize,
}
/// Device tree wrapper struct
pub struct DeviceTree<'a> {
tree: DevTree<'a>,
index: DevTreeIndex<'a, 'a>,
}
impl<'a> DeviceTree<'a> {
/// Constructs a device tree wrapper from the DTB virtual address.
///
/// # Safety
///
/// The caller must ensure the validity of the address.
pub unsafe fn from_addr(virt: usize) -> Self {
let tree = DevTree::from_raw_pointer(virt as _).unwrap();
let index = DevTreeIndex::new(tree, &mut FDT_INDEX_BUFFER.0).unwrap();
Self { tree, index }
}
/// Looks up a node for a given path
pub fn node_by_path(&self, path: &str) -> Option<TNode> {
find_node(self.index.root(), path.trim_start_matches('/'))
}
/// Prints the device tree to log output
pub fn dump(&self, level: LogLevel) {
self.index.root().dump(level, 0)
}
/// Returns the total size of the device tree in memory
pub fn size(&self) -> usize {
self.tree.totalsize()
}
/// Returns the root node's `#address-cells` property, or the default value defined by the
/// specification if it's absent
pub fn address_cells(&self) -> usize {
self.index.root().address_cells()
}
/// Returns the root node's `#size-cells` property, or the default value defined by the
/// specification if it's absent
pub fn size_cells(&self) -> usize {
self.index.root().size_cells()
}
/// Returns the root node of the device tree
pub fn root(&self) -> DevTreeIndexNode {
self.index.root()
}
}
impl<'a, 'i, 'dt> DevTreeIndexNodeExt for DevTreeIndexNode<'a, 'i, 'dt> {
fn get_address_cells(&self) -> Option<usize> {
self.props()
.find(|p| p.name().unwrap_or("") == "#address-cells")
.map(|p| p.u32(0).unwrap() as usize)
}
fn get_size_cells(&self) -> Option<usize> {
self.props()
.find(|p| p.name().unwrap_or("") == "#size-cells")
.map(|p| p.u32(0).unwrap() as usize)
}
fn dump(&self, level: LogLevel, depth: usize) {
fn indent(level: LogLevel, depth: usize) {
for _ in 0..depth {
log_print_raw!(level, " ");
}
}
let node_name = self.name().unwrap();
// Don't dump these
if node_name.starts_with("virtio_mmio@") {
return;
}
indent(level, depth);
log_print_raw!(level, "{:?} {{\n", node_name);
for prop in self.props() {
indent(level, depth + 1);
let name = prop.name().unwrap_or("<???>");
log_print_raw!(level, "{name:?} = ");
match name {
"compatible" | "stdout-path" => {
log_print_raw!(level, "{:?}", prop.str().unwrap_or("<???>"))
}
_ => log_print_raw!(level, "{:x?}", prop.raw()),
}
log_print_raw!(level, "\n");
}
for child in self.children() {
child.dump(level, depth + 1);
}
indent(level, depth);
log_print_raw!(level, "}}\n");
}
}
impl<'a, 'i, 'dt> DevTreeIndexPropExt for DevTreeIndexProp<'a, 'i, 'dt> {
fn read_cell(&self, u32_offset: usize, cell_size: usize) -> Option<u64> {
match cell_size {
1 => self.u32(u32_offset).map(|x| x as u64).ok(),
2 => {
let high = self.u32(u32_offset).ok()? as u64;
let low = self.u32(u32_offset + 1).ok()? as u64;
Some((high << 32) | low)
}
_ => unimplemented!(),
}
}
fn cell1_array_item(&self, index: usize, cells: usize) -> Option<u64> {
self.read_cell(index * cells, cells)
}
fn cell2_array_item(&self, index: usize, cells0: usize, cells1: usize) -> Option<(u64, u64)> {
let u32_index = index * (cells0 + cells1);
let cell0 = self.read_cell(u32_index, cells0)?;
let cell1 = self.read_cell(u32_index + cells0, cells1)?;
Some((cell0, cell1))
}
}
impl<'a> FdtMemoryRegionIter<'a> {
/// Constructs a memory region iterator for given device tree
pub fn new(dt: &'a DeviceTree) -> Self {
let inner = dt.index.root().children();
let address_cells = dt.address_cells();
let size_cells = dt.size_cells();
Self {
inner,
address_cells,
size_cells,
}
}
}
impl Iterator for FdtMemoryRegionIter<'_> {
type Item = PhysicalMemoryRegion;
fn next(&mut self) -> Option<Self::Item> {
loop {
let Some(item) = self.inner.next() else {
break None;
};
let name = item.name().unwrap_or("");
if name.starts_with("memory@") || name == "memory" {
let reg = item
.props()
.find(|p| p.name().unwrap_or("") == "reg")
.unwrap();
let (base, size) = reg
.cell2_array_item(0, self.address_cells, self.size_cells)
.unwrap();
break Some(PhysicalMemoryRegion {
base: base as usize,
size: size as usize,
});
}
}
}
}
/// Looks up a property with given name in the node
pub fn find_prop<'a>(node: &TNode<'a>, name: &str) -> Option<TProp<'a>> {
node.props().find(|p| p.name().unwrap_or("") == name)
}
fn path_component_left(path: &str) -> (&str, &str) {
if let Some((left, right)) = path.split_once('/') {
(left, right.trim_start_matches('/'))
} else {
(path, "")
}
}
fn find_node<'a>(at: TNode<'a>, path: &str) -> Option<TNode<'a>> {
let (item, path) = path_component_left(path);
if item.is_empty() {
assert_eq!(path, "");
Some(at)
} else {
let child = at.children().find(|c| c.name().unwrap() == item)?;
if path.is_empty() {
Some(child)
} else {
find_node(child, path)
}
}
}

View File

@ -8,20 +8,18 @@ use alloc::boxed::Box;
use device_api::{
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable,
IpiDeliveryTarget, IrqNumber, IrqOptions, LocalInterruptController,
IpiDeliveryTarget, IrqOptions, LocalInterruptController,
},
Device,
};
use kernel_util::util::OneTimeInit;
use crate::{
arch::{
aarch64::devtree::{self, DevTreeIndexPropExt},
Architecture, CpuMessage,
},
arch::{aarch64::IrqNumber, Architecture, CpuMessage},
device::devtree::{self, DevTreeIndexPropExt},
device_tree_driver,
mem::device::{DeviceMemory, DeviceMemoryIo},
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
use self::{gicc::Gicc, gicd::Gicd};
@ -71,6 +69,8 @@ impl Device for Gic {
}
impl ExternalInterruptController for Gic {
type IrqNumber = IrqNumber;
fn register_irq(
&self,
irq: IrqNumber,

View File

@ -11,30 +11,34 @@ use aarch64_cpu::{
};
use abi::error::Error;
use device_api::{
interrupt::{
ExternalInterruptController, IpiDeliveryTarget, IrqNumber, LocalInterruptController,
},
interrupt::{ExternalInterruptController, IpiDeliveryTarget, LocalInterruptController},
timer::MonotonicTimestampProviderDevice,
ResetDevice,
};
use fdt_rs::prelude::PropReader;
use git_version::git_version;
use kernel_util::util::OneTimeInit;
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use crate::{
arch::{aarch64::devtree::FdtMemoryRegionIter, Architecture},
debug::{self},
device::{self, power::arm_psci::Psci, DevTreeNodeInfo},
arch::Architecture,
debug,
device::{
self,
devtree::{
self, DevTreeIndexNodePropGet, DevTreeIndexPropExt, DevTreeNodeInfo, DeviceTree,
FdtMemoryRegionIter,
},
power::arm_psci::Psci,
},
fs::{Initrd, INITRD_DATA},
mem::{
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
ConvertAddress,
},
util::OneTimeInit,
};
use self::{
devtree::{DevTreeIndexPropExt, DeviceTree},
smp::CPU_COUNT,
table::{init_fixed_tables, KERNEL_TABLES},
};
@ -44,7 +48,6 @@ use super::CpuMessage;
pub mod boot;
pub mod context;
pub mod cpu;
pub mod devtree;
pub mod exception;
pub mod gic;
pub mod smp;
@ -59,10 +62,16 @@ struct KernelStack {
data: [u8; BOOT_STACK_SIZE],
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IrqNumber {
Private(u32),
Shared(u32),
}
/// AArch64 platform interface
pub struct AArch64 {
dt: OneTimeInit<DeviceTree<'static>>,
ext_intc: OneTimeInit<&'static dyn ExternalInterruptController>,
ext_intc: OneTimeInit<&'static dyn ExternalInterruptController<IrqNumber = IrqNumber>>,
local_intc: OneTimeInit<&'static dyn LocalInterruptController<IpiMessage = CpuMessage>>,
mtimer: OneTimeInit<&'static dyn MonotonicTimestampProviderDevice>,
reset: OneTimeInit<&'static dyn ResetDevice>,
@ -85,6 +94,8 @@ pub static ARCHITECTURE: AArch64 = AArch64 {
};
impl Architecture for AArch64 {
type IrqNumber = IrqNumber;
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
unsafe fn init_mmu(&self, bsp: bool) {
@ -165,7 +176,7 @@ impl Architecture for AArch64 {
fn register_external_interrupt_controller(
&self,
intc: &'static dyn ExternalInterruptController,
intc: &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber>,
) -> Result<(), Error> {
self.ext_intc.init(intc);
Ok(())
@ -192,7 +203,9 @@ impl Architecture for AArch64 {
Ok(())
}
fn external_interrupt_controller(&self) -> &'static dyn ExternalInterruptController {
fn external_interrupt_controller(
&self,
) -> &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
*self.ext_intc.get()
}
@ -272,8 +285,7 @@ impl AArch64 {
fn chosen_stdout_path<'a>(dt: &'a DeviceTree) -> Option<&'a str> {
let chosen = dt.node_by_path("/chosen")?;
let prop = devtree::find_prop(&chosen, "stdout-path")?;
prop.str().ok()
chosen.prop("stdout-path")
}
fn init_platform(&self, bsp: bool) {
@ -294,7 +306,7 @@ impl AArch64 {
node,
};
if let Some((device, _)) = device::probe_dt_node(&probe) {
if let Some((device, _)) = devtree::probe_dt_node(&probe) {
unsafe {
device.init().unwrap();
}
@ -313,7 +325,7 @@ impl AArch64 {
// Probe and initialize the rest of devices
let nodes = dt.root().children();
if let Err(error) = device::enumerate_dt(
if let Err(error) = devtree::enumerate_dt(
address_cells,
size_cells,
nodes,
@ -323,7 +335,7 @@ impl AArch64 {
return Ok(());
}
if let Some((device, _)) = device::probe_dt_node(&probe) {
if let Some((device, _)) = devtree::probe_dt_node(&probe) {
unsafe {
device.init()?;
}

View File

@ -14,7 +14,7 @@ use crate::{
},
};
use super::devtree::{self, DevTreeIndexNodePropGet, DeviceTree};
use crate::device::devtree::{self, DevTreeIndexNodePropGet, DeviceTree};
#[derive(Debug)]
enum CpuEnableMethod {

View File

@ -5,15 +5,11 @@ use core::time::Duration;
use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0};
use abi::error::Error;
use alloc::boxed::Box;
use device_api::{
interrupt::{InterruptHandler, IrqNumber},
timer::MonotonicTimestampProviderDevice,
Device,
};
use device_api::{interrupt::InterruptHandler, timer::MonotonicTimestampProviderDevice, Device};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use crate::{
arch::{Architecture, ARCHITECTURE},
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
device_tree_driver,
proc::wait,
task::tasklet,

View File

@ -19,31 +19,27 @@ macro_rules! absolute_address {
}};
}
pub mod aarch64;
pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
use cfg_if::cfg_if;
// pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
use device_api::{
interrupt::{ExternalInterruptController, IpiDeliveryTarget, LocalInterruptController},
timer::MonotonicTimestampProviderDevice,
ResetDevice,
};
// cfg_if! {
// if #[cfg(target_arch = "aarch64")] {
//
// pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE, PlatformImpl, PLATFORM};
// } else if #[cfg(target_arch = "x86_64")] {
// pub mod x86_64;
//
// pub use x86_64::{
// X86_64 as ArchitectureImpl,
// X86_64 as PlatformImpl,
// ARCHITECTURE,
// ARCHITECTURE as PLATFORM
// };
// } else {
// compile_error!("Architecture is not supported");
// }
// }
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod aarch64;
pub use aarch64::{AArch64 as ArchitectureImpl, ARCHITECTURE};
} else if #[cfg(target_arch = "x86_64")] {
pub mod x86_64;
pub use x86_64::{X86_64 as ArchitectureImpl, ARCHITECTURE};
} else {
compile_error!("Architecture is not supported");
}
}
/// Describes messages sent from some CPU to others
#[derive(Clone, Copy, PartialEq, Debug)]
@ -58,6 +54,9 @@ pub trait Architecture {
/// Address, to which "zero" address is mapped in the virtual address space
const KERNEL_VIRT_OFFSET: usize;
/// IRQ number type associated with the architecture
type IrqNumber;
/// Initializes the memory management unit and sets up virtual memory management.
/// `bsp` flag is provided to make sure mapping tables are only initialized once in a SMP
/// system.
@ -99,7 +98,7 @@ pub trait Architecture {
/// Adds an external interrupt controller to the system
fn register_external_interrupt_controller(
&self,
intc: &'static dyn ExternalInterruptController,
intc: &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber>,
) -> Result<(), Error>;
/// Adds a local interrupt controller to the system
@ -119,15 +118,17 @@ pub trait Architecture {
// TODO only supports 1 extintc per system
/// Returns the primary external interrupt controller
fn external_interrupt_controller(&self) -> &'static dyn ExternalInterruptController;
fn external_interrupt_controller(
&'static self,
) -> &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber>;
/// Returns the local interrupt controller
fn local_interrupt_controller(
&self,
&'static self,
) -> &'static dyn LocalInterruptController<IpiMessage = CpuMessage>;
/// Returns the monotonic timer
fn monotonic_timer(&self) -> &'static dyn MonotonicTimestampProviderDevice;
fn monotonic_timer(&'static self) -> &'static dyn MonotonicTimestampProviderDevice;
/// Sends a message to the requested set of CPUs through an interprocessor interrupt.
///

View File

@ -1,19 +1,21 @@
//! x86-64 I/O APIC driver implementation
use abi::error::Error;
use acpi::platform::interrupt::{Apic as AcpiApic, Polarity, TriggerMode};
use crate::{
arch::x86_64::apic::local::BSP_APIC_ID,
device::{
interrupt::{ExternalInterruptController, InterruptSource},
Device, InitializableDevice,
use device_api::{
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable,
IrqLevel, IrqOptions, IrqTrigger,
},
mem::ConvertAddress,
sync::IrqSafeSpinlock,
util::OneTimeInit,
Device,
};
use super::{IrqNumber, Table, APIC_EXTERNAL_OFFSET};
use crate::{
arch::x86_64::{apic::local::BSP_APIC_ID, IrqNumber},
mem::ConvertAddress,
sync::IrqSafeSpinlock,
};
use super::{APIC_EXTERNAL_OFFSET, MAX_EXTERNAL_VECTORS};
// IRQ 0 is timer, IRQ 1 reserved (for now?), +32 offset for exception entries
const IO_APIC_VECTOR_OFFSET: u32 = 32 + APIC_EXTERNAL_OFFSET;
@ -54,10 +56,10 @@ struct Inner {
/// I/O APIC interface. Provides a way to route and control how interrupts from external devices
/// are handled.
pub struct IoApic {
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
isa_redirections: OneTimeInit<[Option<IsaRedirection>; 16]>,
inner: IrqSafeSpinlock<Inner>,
isa_redirections: [Option<IsaRedirection>; 16],
table: IrqSafeSpinlock<Table>,
table: IrqSafeSpinlock<FixedInterruptTable<{ MAX_EXTERNAL_VECTORS as usize }>>,
}
impl Regs {
@ -108,22 +110,30 @@ impl Inner {
Ok(())
}
fn configure_gsi(&mut self, gsi: u32, active_low: bool, level_triggered: bool) {
fn configure_gsi(&mut self, gsi: u32, options: IrqOptions) {
assert!(gsi < self.max_gsi);
let mut low = self.regs.read(REG_REDIRECTION_BASE + gsi * 2);
if active_low {
match options.level {
IrqLevel::Default => (),
IrqLevel::ActiveLow => {
low |= ENTRY_LOW_POLARITY_LOW;
} else {
}
IrqLevel::ActiveHigh => {
low &= !ENTRY_LOW_POLARITY_LOW;
}
}
if level_triggered {
match options.trigger {
IrqTrigger::Default => (),
IrqTrigger::Level => {
low |= ENTRY_LOW_TRIGGER_LEVEL;
} else {
}
IrqTrigger::Edge => {
low &= !ENTRY_LOW_TRIGGER_LEVEL;
}
}
self.regs.write(REG_REDIRECTION_BASE + gsi * 2, low);
}
@ -144,71 +154,69 @@ impl Inner {
}
impl Device for IoApic {
fn name(&self) -> &'static str {
fn display_name(&self) -> &'static str {
"I/O APIC"
}
unsafe fn init(&'static self) -> Result<(), Error> {
todo!()
}
}
impl ExternalInterruptController for IoApic {
type IrqNumber = IrqNumber;
fn enable_irq(&self, irq: Self::IrqNumber) -> Result<(), Error> {
let mut inner = self.inner.get().lock();
let gsi = self.translate_irq(irq);
inner.set_gsi_enabled(gsi, true);
Ok(())
}
fn register_handler(
fn register_irq(
&self,
irq: Self::IrqNumber,
handler: &'static (dyn InterruptSource + Sync),
options: IrqOptions,
handler: &'static dyn InterruptHandler,
) -> Result<(), Error> {
let mut inner = self.inner.get().lock();
let mut table = self.table.lock();
let mut inner = self.inner.lock();
let table_vector = self.table.lock().insert_least_loaded(handler)?;
// Allocate a vector
let table_vector = table.least_loaded();
let gsi_target_vector = (table_vector as u32) + IO_APIC_VECTOR_OFFSET;
let bsp_apic = *BSP_APIC_ID.get();
infoln!(
"Binding {:?} ({}) to {}:{}",
irq,
handler.name(),
handler.display_name(),
bsp_apic,
table_vector
);
table.add_handler(table_vector, handler)?;
let gsi = self.translate_irq(irq);
inner.map_gsi(gsi, gsi_target_vector, *BSP_APIC_ID.get())?;
inner.configure_gsi(gsi, options);
inner.map_gsi(gsi, gsi_target_vector, bsp_apic)?;
Ok(())
}
fn configure_irq(
&self,
irq: Self::IrqNumber,
active_low: bool,
level_triggered: bool,
) -> Result<(), Error> {
let mut inner = self.inner.get().lock();
fn enable_irq(&self, irq: Self::IrqNumber) -> Result<(), Error> {
let mut inner = self.inner.lock();
let gsi = self.translate_irq(irq);
inner.configure_gsi(gsi, active_low, level_triggered);
inner.set_gsi_enabled(gsi, true);
Ok(())
}
fn handle_specific_irq(&self, gsi: usize) {
let table = self.table.lock();
if let Some(handler) = table.handler(gsi) {
handler.handle_irq();
} else {
warnln!("No handler set for GSI #{}", gsi);
}
}
}
impl InitializableDevice for IoApic {
type Options = AcpiApic;
impl IoApic {
/// Creates an I/O APIC instance from its ACPI definition
pub fn from_acpi(info: &AcpiApic) -> Result<Self, Error> {
let ioapic = info.io_apics.first().unwrap();
unsafe fn init(&self, info: Self::Options) -> Result<(), Error> {
let io_apic = info.io_apics.first().unwrap();
infoln!("I/O APIC at {:#x}", io_apic.address);
infoln!("I/O APIC at {:#x}", ioapic.address);
let mut isa_redirections = [None; 16];
@ -236,8 +244,9 @@ impl InitializableDevice for IoApic {
});
}
// TODO properly map this using DeviceMemory
let regs = Regs {
base: unsafe { (io_apic.address as usize).virtualize() },
base: unsafe { (ioapic.address as usize).virtualize() },
};
let max_gsi = (regs.read(REG_IOAPIC_VERSION) >> 16) & 0xFF;
@ -251,36 +260,15 @@ impl InitializableDevice for IoApic {
inner.set_gsi_enabled(gsi, false);
}
self.inner.init(IrqSafeSpinlock::new(inner));
self.isa_redirections.init(isa_redirections);
Ok(())
}
}
impl IoApic {
/// Constructs an uninitialized I/O APIC interface
pub const fn new() -> Self {
Self {
inner: OneTimeInit::new(),
isa_redirections: OneTimeInit::new(),
table: IrqSafeSpinlock::new(Table::new()),
}
}
/// Handles an interrupt with given GSI number
pub fn handle_irq(&self, gsi: u32) {
let table = self.table.lock();
if let Some(handler) = table.vectors[gsi as usize] {
handler.handle_irq().expect("IRQ handler failed");
} else {
warnln!("No handler set for GSI #{}", gsi);
}
Ok(Self {
isa_redirections,
inner: IrqSafeSpinlock::new(inner),
table: IrqSafeSpinlock::new(FixedInterruptTable::new()),
})
}
fn translate_irq(&self, irq: IrqNumber) -> u32 {
let redir = self.isa_redirections.get();
let redir = &self.isa_redirections;
match irq {
IrqNumber::Isa(isa) => redir[isa as usize]
.map(|t| t.gsi_index)

View File

@ -1,4 +1,6 @@
//! x86-64 Local APIC driver implementation
use device_api::{interrupt::LocalInterruptController, Device};
use kernel_util::util::OneTimeInit;
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@ -6,13 +8,11 @@ use tock_registers::{
};
use crate::{
arch::x86_64::registers::MSR_IA32_APIC_BASE, device::interrupt::IpiDeliveryTarget,
mem::ConvertAddress, util::OneTimeInit,
arch::{x86_64::registers::MSR_IA32_APIC_BASE, CpuMessage},
mem::ConvertAddress,
};
use super::{
APIC_IPI_VECTOR, APIC_LINT0_VECTOR, APIC_LINT1_VECTOR, APIC_SPURIOUS_VECTOR, APIC_TIMER_VECTOR,
};
use super::{APIC_LINT0_VECTOR, APIC_LINT1_VECTOR, APIC_SPURIOUS_VECTOR, APIC_TIMER_VECTOR};
const TIMER_INTERVAL: u32 = 150000;
@ -122,6 +122,31 @@ pub struct LocalApic {
regs: &'static Regs,
}
unsafe impl Send for LocalApic {}
unsafe impl Sync for LocalApic {}
impl Device for LocalApic {
fn display_name(&self) -> &'static str {
"Local APIC"
}
}
impl LocalInterruptController for LocalApic {
type IpiMessage = CpuMessage;
fn send_ipi(
&self,
_target: device_api::interrupt::IpiDeliveryTarget,
_msg: Self::IpiMessage,
) -> Result<(), abi::error::Error> {
todo!()
}
unsafe fn init_ap(&self) -> Result<(), abi::error::Error> {
todo!()
}
}
impl LocalApic {
/// Constructs a new instance of Local APIC.
///
@ -232,28 +257,28 @@ impl LocalApic {
}
}
/// Issues an interprocessor interrupt for the target.
///
/// # Safety
///
/// Unsafe: this function may break the control flow on the target processors.
pub unsafe fn send_ipi(&self, target: IpiDeliveryTarget) {
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
// /// Issues an interprocessor interrupt for the target.
// ///
// /// # Safety
// ///
// /// Unsafe: this function may break the control flow on the target processors.
// pub unsafe fn send_ipi(&self, target: IpiDeliveryTarget) {
// while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
// core::hint::spin_loop();
// }
match target {
IpiDeliveryTarget::AllExceptLocal => {
self.regs.ICR1.write(ICR1::PhysicalDestination.val(0));
self.regs.ICR0.write(
ICR0::Vector.val(APIC_IPI_VECTOR + 32)
+ ICR0::Destination::NMI
+ ICR0::DestinationType::AllExceptThis,
);
}
IpiDeliveryTarget::Specified(_) => todo!(),
}
}
// match target {
// IpiDeliveryTarget::AllExceptLocal => {
// self.regs.ICR1.write(ICR1::PhysicalDestination.val(0));
// self.regs.ICR0.write(
// ICR0::Vector.val(APIC_IPI_VECTOR + 32)
// + ICR0::Destination::NMI
// + ICR0::DestinationType::AllExceptThis,
// );
// }
// IpiDeliveryTarget::Specified(_) => todo!(),
// }
// }
#[inline]
fn base() -> usize {

View File

@ -2,15 +2,15 @@
use core::arch::global_asm;
use abi::error::Error;
use crate::{
arch::{x86_64::cpu::Cpu, PLATFORM},
device::interrupt::IrqHandler,
arch::{x86_64::cpu::Cpu, Architecture},
task::process::Process,
};
use super::exception::{self, IrqFrame};
use super::{
exception::{self, IrqFrame},
ARCHITECTURE,
};
pub mod ioapic;
pub mod local;
@ -32,37 +32,6 @@ pub const APIC_EXTERNAL_OFFSET: u32 = 4;
/// Maximum number of APIC vectors allocated for handling IRQs from I/O APIC
pub const MAX_EXTERNAL_VECTORS: u32 = 16;
/// x86-64 interrupt number wrapper
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum IrqNumber {
/// Legacy (ISA) interrupt. Can have value in range 0..16.
Isa(u8),
/// Global system interrupt. Means an external interrupt for I/O APIC.
Gsi(u8),
}
struct Table {
vectors: [Option<IrqHandler>; MAX_EXTERNAL_VECTORS as usize],
}
impl Table {
pub const fn new() -> Self {
Self {
vectors: [None; MAX_EXTERNAL_VECTORS as usize],
}
}
pub fn add_handler(&mut self, vector: usize, handler: IrqHandler) -> Result<(), Error> {
let old = self.vectors[vector].replace(handler);
assert!(old.is_none());
Ok(())
}
pub fn least_loaded(&self) -> usize {
self.vectors.iter().position(|p| p.is_none()).unwrap()
}
}
/// Fills the IDT with interrupt vectors for this APIC
pub fn setup_vectors(idt: &mut [exception::Entry]) {
extern "C" {
@ -83,7 +52,9 @@ unsafe extern "C" fn irq_handler(vector: usize, frame: *mut IrqFrame) {
let cpu = Cpu::local();
let frame = &mut *frame;
PLATFORM.ioapic.handle_irq(vector as u32);
ARCHITECTURE
.external_interrupt_controller()
.handle_specific_irq(vector);
cpu.local_apic().clear_interrupt();
if let Some(process) = Process::get_current() {

View File

@ -9,18 +9,21 @@ use yboot_proto::{
use crate::{
arch::{
x86_64::{
apic::local::LocalApic, cpu::Cpu, cpuid, exception, kernel_main,
registers::MSR_IA32_KERNEL_GS_BASE, syscall, CPU_INIT_FENCE,
x86_64::{cpuid, exception, registers::MSR_IA32_KERNEL_GS_BASE, BootData},
Architecture, ArchitectureImpl, ARCHITECTURE,
},
Architecture, ArchitectureImpl,
fs::devfs,
kernel_main, kernel_secondary_main,
mem::{
heap,
phys::{self, PageUsage},
ConvertAddress, KERNEL_VIRT_OFFSET,
},
device::platform::Platform,
mem::KERNEL_VIRT_OFFSET,
task,
};
use super::ARCHITECTURE;
use super::smp::CPU_COUNT;
// use super::ARCHITECTURE;
const BOOT_STACK_SIZE: usize = 65536;
@ -76,45 +79,58 @@ unsafe extern "C" fn __x86_64_upper_entry() -> ! {
ARCHITECTURE.init_mmu(true);
core::arch::asm!("wbinvd");
kernel_main(&YBOOT_DATA)
ARCHITECTURE.set_boot_data(BootData::YBoot(&YBOOT_DATA));
ARCHITECTURE
.init_physical_memory()
.expect("Failed to initialize the physical memory manager");
let heap_base = phys::alloc_pages_contiguous(16, PageUsage::Used)
.expect("Couldn't allocate memory for heap");
heap::init_heap(heap_base.virtualize(), 16 * 0x1000);
exception::init_exceptions(0);
devfs::init();
// Initializes: local CPU, platform devices (timers/serials/etc), debug output
ARCHITECTURE.init_platform(0);
cpuid::feature_gate();
kernel_main()
}
/// Application processor entry point
pub extern "C" fn __x86_64_ap_entry() -> ! {
loop {}
// let cpu_id = CPU_COUNT.load(Ordering::Acquire);
let cpu_id = CPU_COUNT.load(Ordering::Acquire);
// MSR_IA32_KERNEL_GS_BASE.set(&UNINIT_CPU as *const _ as u64);
// unsafe {
// core::arch::asm!("swapgs");
// }
// MSR_IA32_KERNEL_GS_BASE.set(&UNINIT_CPU as *const _ as u64);
// unsafe {
// core::arch::asm!("swapgs");
// }
MSR_IA32_KERNEL_GS_BASE.set(&UNINIT_CPU as *const _ as u64);
unsafe {
core::arch::asm!("swapgs");
}
MSR_IA32_KERNEL_GS_BASE.set(&UNINIT_CPU as *const _ as u64);
unsafe {
core::arch::asm!("swapgs");
}
// // Still not initialized: GDT, IDT, CPU features, syscall, kernel_gs_base
// cpuid::feature_gate();
// Still not initialized: GDT, IDT, CPU features, syscall, kernel_gs_base
cpuid::feature_gate();
// infoln!("cpu{} initializing", cpu_id);
// unsafe {
// ARCHITECTURE.init_mmu(false);
// core::arch::asm!("wbinvd");
infoln!("cpu{} initializing", cpu_id);
unsafe {
ARCHITECTURE.init_mmu(false);
core::arch::asm!("wbinvd");
// Cpu::init_local(LocalApic::new(), cpu_id as u32);
// syscall::init_syscall();
// exception::init_exceptions(cpu_id);
exception::init_exceptions(cpu_id);
// ARCHITECTURE.init(false).unwrap();
// }
ARCHITECTURE.init_platform(cpu_id);
}
// CPU_COUNT.fetch_add(1, Ordering::Release);
CPU_COUNT.fetch_add(1, Ordering::Release);
// CPU_INIT_FENCE.wait_one();
// infoln!("cpu{} initialized", cpu_id);
// unsafe { task::enter() }
kernel_secondary_main()
}
global_asm!(

View File

@ -2,12 +2,12 @@
use core::ptr::null_mut;
use alloc::boxed::Box;
use kernel_util::util::OneTimeInit;
use tock_registers::interfaces::Writeable;
use crate::{
arch::x86_64::{gdt, registers::MSR_IA32_KERNEL_GS_BASE},
arch::x86_64::{gdt, registers::MSR_IA32_KERNEL_GS_BASE, syscall},
task::sched::CpuQueue,
util::OneTimeInit,
};
use super::apic::local::LocalApic;
@ -53,6 +53,8 @@ impl Cpu {
MSR_IA32_KERNEL_GS_BASE.set(this as u64);
core::arch::asm!("wbinvd; swapgs");
syscall::init_syscall();
}
/// Returns this CPU's local data structure

View File

@ -2,50 +2,50 @@
use core::{ptr::NonNull, sync::atomic::Ordering};
use abi::error::Error;
use acpi::{
platform::ProcessorInfo, AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping,
};
use acpi::{AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping};
use alloc::boxed::Box;
use cpu::Cpu;
use device_api::{
input::KeyboardProducer,
interrupt::{ExternalInterruptController, IpiDeliveryTarget, LocalInterruptController},
timer::MonotonicTimestampProviderDevice,
Device,
};
use git_version::git_version;
use yboot_proto::{v1::FramebufferOption, AvailableRegion, IterableMemoryMap, LoadProtocolV1};
use kernel_util::util::OneTimeInit;
use yboot_proto::{AvailableRegion, IterableMemoryMap};
use crate::{
arch::x86_64::{
apic::local::LocalApic,
peripherals::serial::ComPort,
table::{init_fixed_tables, KERNEL_TABLES},
},
debug::{self, LogLevel},
device::{
self,
display::{
console::{add_console_autoflush, ConsoleBuffer, ConsoleRow, DisplayConsole},
console::{self, ConsoleBuffer},
fb_console::FramebufferConsole,
linear_fb::LinearFramebuffer,
},
input::KeyboardDevice,
interrupt::{ExternalInterruptController, InterruptSource, IpiDeliveryTarget},
platform::Platform,
timer::TimestampSource,
tty::CombinedTerminal,
InitializableDevice,
tty::combined::CombinedTerminal,
},
fs::{
devfs::{self, CharDeviceType},
Initrd, INITRD_DATA,
},
mem::{
heap,
phys::{self, reserved::reserve_region, PageUsage, PhysicalMemoryRegion},
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
ConvertAddress,
},
sync::SpinFence,
task,
util::OneTimeInit,
CPU_INIT_FENCE,
};
use self::{
apic::{ioapic::IoApic, IrqNumber},
apic::ioapic::IoApic,
intrinsics::IoPort,
peripherals::{hpet::Hpet, ps2::PS2Controller, serial::ComPort},
peripherals::{hpet::Hpet, ps2::PS2Controller},
smp::CPU_COUNT,
};
@ -67,7 +67,14 @@ pub mod smp;
pub mod syscall;
pub mod table;
static CPU_INIT_FENCE: SpinFence = SpinFence::new();
/// x86-64 interrupt number wrapper
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum IrqNumber {
/// Legacy (ISA) interrupt. Can have value in range 0..16.
Isa(u8),
/// Global system interrupt. Means an external interrupt for I/O APIC.
Gsi(u8),
}
/// Helper trait to provide abstract access to available memory regions
pub trait AbstractAvailableRegion {
@ -119,6 +126,27 @@ impl<'a, T: IterableMemoryMap<'a> + 'a> AbstractMemoryMap<'a> for T {
#[derive(Clone, Copy)]
struct AcpiHandlerImpl;
struct SimpleLogger;
impl log::Log for SimpleLogger {
fn enabled(&self, _metadata: &log::Metadata) -> bool {
true
}
fn log(&self, record: &log::Record) {
match record.level() {
log::Level::Warn => warnln!("{}", record.args()),
log::Level::Info => infoln!("{}", record.args()),
log::Level::Trace | log::Level::Debug => infoln!("{}", record.args()),
log::Level::Error => errorln!("{}", record.args()),
}
}
fn flush(&self) {}
}
static LOGGER: SimpleLogger = SimpleLogger;
impl AcpiHandler for AcpiHandlerImpl {
// No actual address space modification is performed
unsafe fn map_physical_region<T>(
@ -143,28 +171,44 @@ impl AcpiHandler for AcpiHandlerImpl {
fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
}
/// Describes which kind of bootloader data was provided to the kernel
pub enum BootData {
/// [yboot_proto::LoadProtocolV1]
YBoot(&'static yboot_proto::LoadProtocolV1),
}
/// x86-64 architecture + platform implementation
pub struct X86_64 {
yboot_framebuffer: OneTimeInit<FramebufferOption>,
rsdp_phys_base: OneTimeInit<usize>,
boot_data: OneTimeInit<BootData>,
acpi: OneTimeInit<AcpiTables<AcpiHandlerImpl>>,
acpi_processor_info: OneTimeInit<ProcessorInfo>,
// TODO make this fully dynamic?
framebuffer: OneTimeInit<LinearFramebuffer>,
fb_console: OneTimeInit<FramebufferConsole>,
combined_terminal: OneTimeInit<CombinedTerminal>,
// Static devices with dynamic addresses
ioapic: IoApic,
timer: Hpet,
// Static devices
ps2: PS2Controller,
com1_3: ComPort,
ioapic: OneTimeInit<IoApic>,
timer: OneTimeInit<Hpet>,
}
/// x86-64 architecture implementation
pub static ARCHITECTURE: X86_64 = X86_64 {
boot_data: OneTimeInit::new(),
acpi: OneTimeInit::new(),
framebuffer: OneTimeInit::new(),
fb_console: OneTimeInit::new(),
combined_terminal: OneTimeInit::new(),
// Devices
ioapic: OneTimeInit::new(),
timer: OneTimeInit::new(),
};
impl Architecture for X86_64 {
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
type IrqNumber = IrqNumber;
unsafe fn init_mmu(&self, bsp: bool) {
if bsp {
init_fixed_tables();
@ -174,16 +218,6 @@ impl Architecture for X86_64 {
core::arch::asm!("wbinvd; mov {0}, %cr3", in(reg) cr3, options(att_syntax));
}
fn map_device_pages(&self, phys: usize, count: usize) -> Result<usize, Error> {
unsafe { KERNEL_TABLES.map_device_pages(phys, count) }
}
fn wait_for_interrupt() {
unsafe {
core::arch::asm!("hlt");
}
}
unsafe fn set_interrupt_mask(mask: bool) {
if mask {
core::arch::asm!("cli");
@ -201,98 +235,18 @@ impl Architecture for X86_64 {
flags & (1 << 9) == 0
}
fn cpu_count() -> usize {
CPU_COUNT.load(Ordering::Acquire)
fn wait_for_interrupt() {
unsafe {
core::arch::asm!("hlt");
}
}
impl Platform for X86_64 {
type IrqNumber = apic::IrqNumber;
const KERNEL_PHYS_BASE: usize = 0x400000;
unsafe fn init(&'static self, is_bsp: bool) -> Result<(), Error> {
if is_bsp {
Self::disable_8259();
// Initialize I/O APIC from ACPI
let rsdp = *self.rsdp_phys_base.get();
let acpi_tables = AcpiTables::from_rsdp(AcpiHandlerImpl, rsdp).unwrap();
let hpet = HpetInfo::new(&acpi_tables).unwrap();
let platform_info = acpi_tables.platform_info().unwrap();
if let Some(processor_info) = platform_info.processor_info {
self.acpi_processor_info.init(processor_info);
// CPU management
unsafe fn reset(&self) -> ! {
todo!()
}
let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else {
panic!("Processor does not have APIC");
};
self.ioapic.init(apic_info)?;
self.timer.init(hpet).unwrap();
// Enable IRQs for the devices
self.ps2.init_irq()?;
self.timer.init_irq()?;
// Add a terminal to the devfs
// TODO this is ugly
let combined_terminal = CombinedTerminal::new(&self.ps2, FB_CONSOLE.get());
self.combined_terminal.init(combined_terminal);
self.ps2.attach(self.combined_terminal.get());
devfs::add_char_device(self.combined_terminal.get(), CharDeviceType::TtyRegular)?;
}
Ok(())
}
unsafe fn init_debug(&'static self) {
// Serial output
self.com1_3.init(()).ok();
debug::add_sink(self.com1_3.port_a(), LogLevel::Debug);
// Graphical output
if let Some(fb) = self.yboot_framebuffer.try_get() {
LINEAR_FB.init(
LinearFramebuffer::from_physical_bits(
fb.res_address as _,
fb.res_size as _,
fb.res_stride as _,
fb.res_width,
fb.res_height,
)
.unwrap(),
);
FB_CONSOLE.init(FramebufferConsole::from_framebuffer(
LINEAR_FB.get(),
&bitmap_font::tamzen::FONT_6x12,
ConsoleBuffer::fixed(&mut EARLY_CONSOLE_BUFFER, 32),
));
debug::add_sink(FB_CONSOLE.get(), LogLevel::Info);
}
debug::reset();
}
fn name(&self) -> &'static str {
"x86-64"
}
fn interrupt_controller(
&self,
) -> &dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
&self.ioapic
}
fn timestamp_source(&self) -> &dyn TimestampSource {
&self.timer
}
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, _msg: CpuMessage) -> Result<(), Error> {
unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: CpuMessage) -> Result<(), Error> {
if !CPU_INIT_FENCE.try_wait_all(1) {
// Don't send an IPI: SMP not initialized yet
return Ok(());
@ -302,99 +256,94 @@ impl Platform for X86_64 {
panic!("Local APIC has not been initialized yet");
};
local_apic.send_ipi(target);
local_apic.send_ipi(target, msg)
}
Ok(())
unsafe fn start_application_processors(&self) {
if let Some(acpi) = self.acpi.try_get() {
let Some(pinfo) = acpi.platform_info().ok().and_then(|p| p.processor_info) else {
return;
};
smp::start_ap_cores(&pinfo);
}
}
fn cpu_count() -> usize {
CPU_COUNT.load(Ordering::Acquire)
}
// Memory
fn map_device_pages(&self, phys: usize, count: usize) -> Result<usize, Error> {
unsafe { KERNEL_TABLES.map_device_pages(phys, count) }
}
// Devices
fn register_monotonic_timer(
&self,
_timer: &'static dyn device_api::timer::MonotonicTimestampProviderDevice,
) -> Result<(), Error> {
todo!()
}
fn register_local_interrupt_controller(
&self,
_intc: &'static dyn device_api::interrupt::LocalInterruptController<
IpiMessage = CpuMessage,
>,
) -> Result<(), Error> {
todo!()
}
fn register_external_interrupt_controller(
&self,
_intc: &'static dyn device_api::interrupt::ExternalInterruptController<
IrqNumber = Self::IrqNumber,
>,
) -> Result<(), Error> {
todo!()
}
fn register_reset_device(
&self,
_reset: &'static dyn device_api::ResetDevice,
) -> Result<(), Error> {
todo!()
}
fn monotonic_timer(&'static self) -> &'static dyn MonotonicTimestampProviderDevice {
self.timer.get()
}
fn local_interrupt_controller(
&'static self,
) -> &'static dyn LocalInterruptController<IpiMessage = CpuMessage> {
todo!()
}
fn external_interrupt_controller(
&'static self,
) -> &'static dyn ExternalInterruptController<IrqNumber = Self::IrqNumber> {
self.ioapic.get()
}
}
impl X86_64 {
unsafe fn init_physical_memory<'a, M: AbstractMemoryMap<'a>>(memory_map: &M) {
// Reserve the lower 8MiB of memory
reserve_region(
"lower-memory",
PhysicalMemoryRegion {
base: 0,
size: 8 << 21,
},
);
// Reserve memory map
reserve_region("memory-map", memory_map.reserved_range());
if let Some(initrd) = INITRD_DATA.try_get() {
reserve_region(
"initrd",
PhysicalMemoryRegion {
base: initrd.phys_page_start,
size: initrd.phys_page_len,
},
fn set_boot_data(&self, boot_data: BootData) {
match &boot_data {
BootData::YBoot(data) => {
// Setup initrd
Self::init_initrd(
data.initrd_address as usize,
(data.initrd_address + data.initrd_size) as usize,
);
}
phys::init_from_iter(memory_map.iter().map(|r| PhysicalMemoryRegion {
base: r.start_address(),
size: r.page_count() * 0x1000,
}))
.expect("Failed to initialize the physical memory manager");
// Reallocate the console buffer
FB_CONSOLE
.get()
.reallocate_buffer()
.expect("Failed to reallocate console buffer");
}
fn init_rsdp(&self, phys: usize) {
self.rsdp_phys_base.init(phys);
self.boot_data.init(boot_data);
}
unsafe fn disable_8259() {
infoln!("Disabling i8259 PIC");
// TODO should I make a module for 8259 if I don't even use it?
let pic_master_cmd = IoPort::new(0x20);
let pic_master_data = IoPort::new(0x21);
let pic_slave_cmd = IoPort::new(0xA0);
let pic_slave_data = IoPort::new(0xA1);
// Remap PIC IRQ vectors to 32..
pic_master_cmd.write(0x11);
pic_slave_cmd.write(0x11);
pic_master_data.write(32);
pic_slave_data.write(32 + 8);
pic_slave_data.write(0xFF);
pic_master_data.write(0xFF);
pic_master_cmd.write(0x20);
pic_slave_cmd.write(0x20);
}
}
/// x86-64 architecture + platform implementation
pub static ARCHITECTURE: X86_64 = X86_64 {
rsdp_phys_base: OneTimeInit::new(),
yboot_framebuffer: OneTimeInit::new(),
acpi_processor_info: OneTimeInit::new(),
combined_terminal: OneTimeInit::new(),
ioapic: IoApic::new(),
timer: Hpet::uninit(),
ps2: PS2Controller::new(IrqNumber::Isa(1), IrqNumber::Isa(12), 0x64, 0x60),
com1_3: ComPort::new(0x3F8, 0x3E8, IrqNumber::Isa(4)),
};
static LINEAR_FB: OneTimeInit<LinearFramebuffer> = OneTimeInit::new();
static FB_CONSOLE: OneTimeInit<FramebufferConsole> = OneTimeInit::new();
const EARLY_BUFFER_LINES: usize = 32;
static mut EARLY_CONSOLE_BUFFER: [ConsoleRow; EARLY_BUFFER_LINES] =
[ConsoleRow::zeroed(); EARLY_BUFFER_LINES];
fn setup_initrd(initrd_start: usize, initrd_end: usize) {
fn init_initrd(initrd_start: usize, initrd_end: usize) {
if initrd_start == 0 || initrd_end <= initrd_start {
infoln!("No initrd loaded");
return;
@ -419,72 +368,180 @@ fn setup_initrd(initrd_start: usize, initrd_end: usize) {
INITRD_DATA.init(initrd);
}
fn kernel_main(boot_data: &LoadProtocolV1) -> ! {
ARCHITECTURE
.yboot_framebuffer
.init(boot_data.opt_framebuffer);
unsafe {
ARCHITECTURE.init_debug();
fn init_acpi_from_boot_data(&self) {
match *self.boot_data.get() {
BootData::YBoot(data) => {
self.init_acpi_from_rsdp(data.rsdp_address as usize);
}
infoln!("Yggdrasil kernel git {} starting", git_version!());
cpuid::feature_gate();
if boot_data.memory_map.address > 0xFFFFFFFF {
errorln!("Unhandled case: memory map is above 4GiB");
loop {
X86_64::wait_for_interrupt();
}
}
if boot_data.rsdp_address != 0 {
infoln!("ACPI RSDP at {:#x}", boot_data.rsdp_address);
ARCHITECTURE.init_rsdp(boot_data.rsdp_address as _);
fn init_acpi_from_rsdp(&self, address: usize) {
let acpi_tables = unsafe { AcpiTables::from_rsdp(AcpiHandlerImpl, address).unwrap() };
self.acpi.init(acpi_tables);
}
unsafe fn init_physical_memory(&self) -> Result<(), Error> {
// Reserve the lower 8MiB of memory
reserve_region(
"lower-memory",
PhysicalMemoryRegion {
base: 0,
size: 8 << 21,
},
);
// Reserve initrd
let initrd_start = boot_data.initrd_address as usize;
let initrd_end = initrd_start + boot_data.initrd_size as usize;
setup_initrd(initrd_start, initrd_end);
// Setup physical memory allocation
unsafe {
X86_64::init_physical_memory(&boot_data.memory_map);
if let Some(initrd) = INITRD_DATA.try_get() {
reserve_region(
"initrd",
PhysicalMemoryRegion {
base: initrd.phys_page_start,
size: initrd.phys_page_len,
},
);
}
// Allocate memory for the kernel heap
let heap_base = phys::alloc_pages_contiguous(16, PageUsage::Used)
.expect("Could not allocate a block for heap");
unsafe {
heap::init_heap(heap_base.virtualize(), 16 * 0x1000);
match *self.boot_data.get() {
BootData::YBoot(data) => {
let memory_map = &data.memory_map;
reserve_region("memory-map", memory_map.reserved_range());
phys::init_from_iter(IterableMemoryMap::iter(memory_map).map(|r| {
PhysicalMemoryRegion {
base: AbstractAvailableRegion::start_address(r),
size: AbstractAvailableRegion::page_count(r) * 0x1000,
}
// Add console to flush list
add_console_autoflush(FB_CONSOLE.get());
// Also initializes local APIC
unsafe {
Cpu::init_local(LocalApic::new(), 0);
syscall::init_syscall();
// TODO per-CPU IDTs?
exception::init_exceptions(0);
devfs::init();
ARCHITECTURE.init(true).unwrap();
if let Some(info) = ARCHITECTURE.acpi_processor_info.try_get() {
smp::start_ap_cores(info);
}
CPU_INIT_FENCE.signal();
task::init().expect("Failed to initialize the scheduler");
task::enter()
}))
.expect("Failed to initialize the physical memory manager");
}
}
Ok(())
}
unsafe fn init_platform_from_acpi(&self, acpi: &AcpiTables<AcpiHandlerImpl>) {
let platform_info = acpi.platform_info().unwrap();
let InterruptModel::Apic(apic_info) = platform_info.interrupt_model else {
panic!("Processor does not have an APIC");
};
self.ioapic.init(IoApic::from_acpi(&apic_info).unwrap());
let hpet = HpetInfo::new(acpi).unwrap();
self.timer.init(Hpet::from_acpi(&hpet).unwrap());
}
unsafe fn init_framebuffer(&'static self) {
match *self.boot_data.get() {
BootData::YBoot(data) => {
let fb = &data.opt_framebuffer;
self.framebuffer.init(
LinearFramebuffer::from_physical_bits(
fb.res_address as _,
fb.res_size as _,
fb.res_stride as _,
fb.res_width as _,
fb.res_height as _,
)
.unwrap(),
);
}
}
self.fb_console.init(FramebufferConsole::from_framebuffer(
self.framebuffer.get(),
None,
ConsoleBuffer::new(32).unwrap(),
));
debug::add_sink(self.fb_console.get(), LogLevel::Info);
// Add a terminal to the devfs
// TODO this is ugly
let combined_terminal = CombinedTerminal::new(self.fb_console.get());
self.combined_terminal.init(combined_terminal);
devfs::add_char_device(self.combined_terminal.get(), CharDeviceType::TtyRegular).unwrap();
console::add_console_autoflush(self.fb_console.get());
}
unsafe fn init_platform(&'static self, cpu_id: usize) {
Cpu::init_local(LocalApic::new(), cpu_id as _);
if cpu_id == 0 {
self.init_acpi_from_boot_data();
Self::disable_8259();
// Initialize debug output as soon as possible
let com1_3 = Box::leak(Box::new(ComPort::new(0x3F8, 0x3E8, IrqNumber::Isa(4))));
debug::add_sink(com1_3.port_a(), LogLevel::Debug);
// devfs::add_char_device(com1_3.port_a(), CharDeviceType::TtySerial).unwrap();
self.init_framebuffer();
debug::reset();
log::set_logger(&LOGGER)
.map(|_| log::set_max_level(log::LevelFilter::Trace))
.ok();
let ps2 = Box::leak(Box::new(PS2Controller::new(
IrqNumber::Isa(1),
IrqNumber::Isa(12),
0x64,
0x60,
)));
ps2.init().unwrap();
// Print some stuff now that the output is initialized
infoln!(
"Yggdrasil v{} ({})",
env!("CARGO_PKG_VERSION"),
git_version!()
);
infoln!("Initializing x86_64 platform");
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi);
}
// Enable IRQs for the devices
self.timer.get().init_irq().unwrap();
ps2.connect(self.combined_terminal.get());
ps2.init_irq().unwrap();
device::register_device(self.ioapic.get());
device::register_device(self.timer.get());
device::register_device(ps2);
infoln!("Device list:");
for device in device::manager_lock().devices() {
infoln!("* {}", device.display_name());
}
}
}
unsafe fn disable_8259() {
infoln!("Disabling i8259 PIC");
// TODO should I make a module for 8259 if I don't even use it?
let pic_master_cmd = IoPort::new(0x20);
let pic_master_data = IoPort::new(0x21);
let pic_slave_cmd = IoPort::new(0xA0);
let pic_slave_data = IoPort::new(0xA1);
// Remap PIC IRQ vectors to 32..
pic_master_cmd.write(0x11);
pic_slave_cmd.write(0x11);
pic_master_data.write(32);
pic_slave_data.write(32 + 8);
pic_slave_data.write(0xFF);
pic_master_data.write(0xFF);
pic_master_cmd.write(0x20);
pic_slave_cmd.write(0x20);
}
}

View File

@ -3,6 +3,11 @@ use core::time::Duration;
use abi::error::Error;
use acpi::hpet::HpetInfo as AcpiHpet;
use device_api::{
interrupt::{InterruptHandler, IrqLevel, IrqOptions, IrqTrigger},
timer::MonotonicTimestampProviderDevice,
Device,
};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@ -10,16 +15,11 @@ use tock_registers::{
};
use crate::{
arch::{x86_64::apic::IrqNumber, PLATFORM},
device::{
interrupt::InterruptSource, platform::Platform, timer::TimestampSource, Device,
InitializableDevice,
},
arch::{x86_64::IrqNumber, Architecture, ARCHITECTURE},
mem::device::DeviceMemoryIo,
proc::wait,
sync::IrqSafeSpinlock,
task::tasklet,
util::OneTimeInit,
};
register_bitfields! {
@ -102,7 +102,7 @@ struct Inner {
/// HPET timer group interface
pub struct Hpet {
inner: OneTimeInit<IrqSafeSpinlock<Inner>>,
inner: IrqSafeSpinlock<Inner>,
}
impl Inner {
@ -135,17 +135,17 @@ impl Inner {
}
}
impl TimestampSource for Hpet {
fn timestamp(&self) -> Result<Duration, Error> {
let inner = self.inner.get().lock();
impl MonotonicTimestampProviderDevice for Hpet {
fn monotonic_timestamp(&self) -> Result<Duration, Error> {
let inner = self.inner.lock();
Ok(Duration::from_millis(inner.tim0_counter))
}
}
impl InterruptSource for Hpet {
fn handle_irq(&self) -> Result<bool, Error> {
impl InterruptHandler for Hpet {
fn handle_irq(&self) -> bool {
let now = {
let mut inner = self.inner.get().lock();
let mut inner = self.inner.lock();
inner.regs.GeneralInterruptStatus.set(1);
inner.tim0_counter = inner.tim0_counter.wrapping_add(1);
@ -155,7 +155,13 @@ impl InterruptSource for Hpet {
wait::tick(now);
tasklet::tick(now);
Ok(true)
true
}
}
impl Device for Hpet {
fn display_name(&self) -> &'static str {
"HPET"
}
unsafe fn init_irq(&'static self) -> Result<(), Error> {
@ -163,8 +169,8 @@ impl InterruptSource for Hpet {
const FS_IN_MS: u64 = 1000000000000;
// Configure timer 0
let intc = PLATFORM.interrupt_controller();
let mut inner = self.inner.get().lock();
let intc = ARCHITECTURE.external_interrupt_controller();
let mut inner = self.inner.lock();
// Calculate the interrupt period
let clk_period = inner
@ -206,9 +212,15 @@ impl InterruptSource for Hpet {
let tim0_irq = tim0_irq.expect("Could not pick an IRQ for HPET TIM0");
// Bind and enable the IRQ
let irq = IrqNumber::Gsi(tim0_irq as _);
intc.register_handler(irq, self)?;
intc.configure_irq(irq, true, true)?;
let irq = IrqNumber::Gsi(tim0_irq);
intc.register_irq(
irq,
IrqOptions {
level: IrqLevel::ActiveLow,
trigger: IrqTrigger::Level,
},
self,
)?;
intc.enable_irq(irq)?;
// Disable FSB interrupt route and 32 bit mode
@ -245,32 +257,16 @@ impl InterruptSource for Hpet {
}
}
impl InitializableDevice for Hpet {
type Options = AcpiHpet;
unsafe fn init(&self, info: Self::Options) -> Result<(), Error> {
impl Hpet {
/// Creates a HPET instance from its ACPI definition
pub fn from_acpi(info: &AcpiHpet) -> Result<Self, Error> {
infoln!("Initializing HPET:");
infoln!("Address: {:#x}", info.base_address);
let inner = unsafe { Inner::new(info.base_address) }?;
self.inner.init(IrqSafeSpinlock::new(inner));
Ok(())
}
}
impl Device for Hpet {
fn name(&self) -> &'static str {
"HPET"
}
}
impl Hpet {
/// Constructs an uninitialized HPET instance
pub const fn uninit() -> Self {
Self {
inner: OneTimeInit::new(),
}
Ok(Self {
inner: IrqSafeSpinlock::new(inner),
})
}
}

View File

@ -1,14 +1,15 @@
//! Intel 8042 PS/2 controller driver implemenation
use abi::error::Error;
use device_api::{
input::{KeyboardConsumer, KeyboardProducer},
interrupt::InterruptHandler,
Device,
};
use crate::{
arch::{
x86_64::{apic::IrqNumber, intrinsics::IoPort},
PLATFORM,
},
device::{
input::KeyboardDevice, interrupt::InterruptSource, platform::Platform, tty::TtyDevice,
Device,
x86_64::{intrinsics::IoPort, IrqNumber},
Architecture, ARCHITECTURE,
},
sync::IrqSafeSpinlock,
};
@ -24,7 +25,7 @@ struct Inner {
shift: bool,
ctrl: bool,
tty: Option<&'static dyn TtyDevice<16>>,
consumer: Option<&'static dyn KeyboardConsumer>, // tty: Option<&'static dyn TtyDevice<16>>,
}
/// PS/2 controller driver
@ -80,37 +81,14 @@ impl Inner {
}
}
impl KeyboardDevice for PS2Controller {
fn attach(&self, terminal: &'static dyn TtyDevice<16>) {
self.inner.lock().tty.replace(terminal);
impl KeyboardProducer for PS2Controller {
fn connect(&self, to: &'static dyn KeyboardConsumer) {
self.inner.lock().consumer.replace(to);
}
}
impl InterruptSource for PS2Controller {
unsafe fn init_irq(&'static self) -> Result<(), Error> {
let mut inner = self.inner.lock();
let intc = PLATFORM.interrupt_controller();
intc.register_handler(self.primary_irq, self)?;
// Disable PS/2 devices from sending any further data
inner.send_command(0xAD);
inner.send_command(0xA7);
// Flush the buffer
while inner.command.read() & Inner::STATUS_OUTPUT_FULL != 0 {
inner.data.read();
}
// Enable primary port
inner.send_command(0xAE);
intc.enable_irq(self.primary_irq)?;
Ok(())
}
fn handle_irq(&self) -> Result<bool, Error> {
impl InterruptHandler for PS2Controller {
fn handle_irq(&self) -> bool {
let mut count = 0;
let mut inner = self.inner.lock();
loop {
@ -177,21 +155,49 @@ impl InterruptSource for PS2Controller {
continue;
}
if let Some(tty) = inner.tty {
tty.recv_byte(key);
if let Some(consumer) = inner.consumer {
consumer.handle_character(key).ok();
}
count += 1;
}
Ok(count != 0)
count != 0
}
}
impl Device for PS2Controller {
fn name(&self) -> &'static str {
fn display_name(&self) -> &'static str {
"PS/2 Controller"
}
unsafe fn init(&'static self) -> Result<(), Error> {
Ok(())
}
unsafe fn init_irq(&'static self) -> Result<(), Error> {
let mut inner = self.inner.lock();
// let intc = PLATFORM.interrupt_controller();
let intc = ARCHITECTURE.external_interrupt_controller();
intc.register_irq(self.primary_irq, Default::default(), self)?;
// Disable PS/2 devices from sending any further data
inner.send_command(0xAD);
inner.send_command(0xA7);
// Flush the buffer
while inner.command.read() & Inner::STATUS_OUTPUT_FULL != 0 {
inner.data.read();
}
// Enable primary port
inner.send_command(0xAE);
intc.enable_irq(self.primary_irq)?;
Ok(())
}
}
impl PS2Controller {
@ -207,7 +213,7 @@ impl PS2Controller {
data: IoPort::new(data_port),
shift: false,
ctrl: false,
tty: None,
consumer: None,
};
Self {

View File

@ -1,9 +1,10 @@
//! Driver for x86 COM ports
use abi::error::Error;
use device_api::{serial::SerialDevice, Device};
use crate::{
arch::x86_64::{apic::IrqNumber, intrinsics::IoPort},
arch::x86_64::{intrinsics::IoPort, IrqNumber},
debug::DebugSink,
device::{serial::SerialDevice, Device, InitializableDevice},
sync::IrqSafeSpinlock,
};
@ -13,11 +14,13 @@ struct Inner {
lsr: IoPort<u8>,
}
/// Single port of the COM port pair
pub struct Port {
inner: IrqSafeSpinlock<Inner>,
}
// Port pair
/// COM port pair
#[allow(unused)]
pub struct ComPort {
port_a: Port,
port_b: Port,
@ -41,22 +44,22 @@ impl SerialDevice for Port {
inner.dr.write(byte);
Ok(())
}
fn receive(&self, blocking: bool) -> Result<u8, Error> {
todo!()
}
}
impl Device for Port {
fn name(&self) -> &'static str {
"com-port"
fn display_name(&self) -> &'static str {
"COM port"
}
unsafe fn init(&'static self) -> Result<(), Error> {
Ok(())
}
}
impl Port {
const LSR_THRE: u8 = 1 << 5;
pub const fn new(base: u16) -> Self {
const fn new(base: u16) -> Self {
Self {
inner: IrqSafeSpinlock::new(Inner {
dr: IoPort::new(base),
@ -66,16 +69,8 @@ impl Port {
}
}
impl InitializableDevice for ComPort {
type Options = ();
unsafe fn init(&self, _opts: Self::Options) -> Result<(), Error> {
// TODO proper init
Ok(())
}
}
impl ComPort {
/// Constructs a COM port pair
pub const fn new(port_a: u16, port_b: u16, irq: IrqNumber) -> Self {
Self {
port_a: Port::new(port_a),
@ -84,6 +79,7 @@ impl ComPort {
}
}
/// Returns a reference to the A port of this COM pair
pub fn port_a(&self) -> &Port {
&self.port_a
}

View File

@ -2,8 +2,9 @@
use core::fmt::{self, Arguments};
use abi::error::Error;
use kernel_util::util::StaticVector;
use crate::{sync::IrqSafeSpinlock, util::StaticVector};
use crate::sync::IrqSafeSpinlock;
const MAX_DEBUG_SINKS: usize = 4;

View File

@ -1,3 +1,4 @@
//! Bus devices
#[cfg(feature = "device-tree")]
pub mod simple_bus;

View File

@ -1,6 +1,6 @@
//! Simple "passthrough" bus device
use crate::{arch::aarch64::devtree::DevTreeIndexNodeExt, device, device_tree_driver};
use crate::{device::devtree, device_tree_driver};
device_tree_driver! {
compatible: ["simple-bus"],
@ -11,8 +11,8 @@ device_tree_driver! {
let nodes = dt.node.children();
// Iterate devices on the bus
device::enumerate_dt(address_cells, size_cells, nodes, |_, probe| {
if let Some((device, _)) = device::probe_dt_node(&probe) {
devtree::enumerate_dt(address_cells, size_cells, nodes, |_, probe| {
if let Some((device, _)) = devtree::probe_dt_node(&probe) {
unsafe {
device.init()?;
}

454
src/device/devtree.rs Normal file
View File

@ -0,0 +1,454 @@
//! ARM device tree utlities
use core::mem::size_of;
use abi::error::Error;
use alloc::boxed::Box;
use device_api::{Device, DeviceId};
use fdt_rs::{
base::DevTree,
index::{iters::DevTreeIndexNodeSiblingIter, DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp},
prelude::PropReader,
};
use crate::{debug::LogLevel, mem::phys::PhysicalMemoryRegion};
use super::register_device;
/// Helper macro to return the count of expressions supplied to it
#[macro_export]
macro_rules! count {
() => (0usize);
($x:tt $($xs:tt)*) => (1usize + $crate::count!($($xs)*));
}
/// Registers a device driver for compatible device tree nodes
///
/// # Usage example
///
/// ```
/// device_tree_driver! {
/// compatible: ["arm,pl011"],
/// probe(of) => {
/// let my_device = ...; // ... extract some info about the device ...
/// Some(Box::new(my_device))
/// }
/// }
/// ```
#[macro_export]
macro_rules! device_tree_driver {
(
compatible: [$($compatible:literal),+],
probe ($node:ident) => $probe_body:block $(,)?
) => {
const __COMPATIBLE_LEN: usize = $crate::count!($($compatible )+);
static __COMPATIBLE: [&str; __COMPATIBLE_LEN] = [$($compatible),+];
fn __probe($node: &$crate::device::devtree::DevTreeNodeInfo) ->
Option<alloc::boxed::Box<dyn device_api::Device>> $probe_body
core::arch::global_asm!(r#"
.pushsection .dt_probes, "a"
.quad {compatible}
.quad {compatible_len}
.quad {probe_func}
.popsection
"#,
compatible = sym __COMPATIBLE,
compatible_len = const __COMPATIBLE_LEN,
probe_func = sym __probe
);
};
}
const INDEX_BUFFER_SIZE: usize = 65536;
#[repr(C, align(0x10))]
struct FdtIndexBuffer([u8; INDEX_BUFFER_SIZE]);
static mut FDT_INDEX_BUFFER: FdtIndexBuffer = FdtIndexBuffer::zeroed();
impl FdtIndexBuffer {
const fn zeroed() -> Self {
Self([0; INDEX_BUFFER_SIZE])
}
}
/// Device tree node
pub type TNode<'a> = DevTreeIndexNode<'a, 'a, 'a>;
/// Device tree property
pub type TProp<'a> = DevTreeIndexProp<'a, 'a, 'a>;
/// Helper trait to provide extra functionality for [DevTreeIndexProp]
pub trait DevTreeIndexPropExt {
/// Reads a cell value from single-type cell array at given cell index
fn cell1_array_item(&self, index: usize, cells: usize) -> Option<u64>;
/// Reads a cell pair from cell pair array at given pair index
fn cell2_array_item(&self, index: usize, cells0: usize, cells1: usize) -> Option<(u64, u64)>;
/// Reads a cell value from the property at given offset
fn read_cell(&self, u32_offset: usize, cell_size: usize) -> Option<u64>;
}
/// Helper trait to provide extra functionality for [DevTreeIndexNode]
pub trait DevTreeIndexNodeExt {
/// Returns the root node's `#address-cells` property, or the default value defined by the
/// specification if it's absent
fn address_cells(&self) -> usize {
self.get_address_cells().unwrap_or(2)
}
/// Returns the root node's `#size-cells` property, or the default value defined by the
/// specification if it's absent
fn size_cells(&self) -> usize {
self.get_size_cells().unwrap_or(1)
}
/// Returns the #address-cells property of the node, if there is one
fn get_address_cells(&self) -> Option<usize>;
/// Returns the #size-cells property of the node, if there is one
fn get_size_cells(&self) -> Option<usize>;
/// Prints the node contents to debug output
fn dump(&self, level: LogLevel, depth: usize);
}
/// Extension trait for [DevTreeIndexNode] to obtain typed property values
pub trait DevTreeIndexNodePropGet<T> {
/// Returns a property value of given type, if it exists
fn prop(&self, name: &str) -> Option<T>;
}
impl<'a, 'i, 'dt> DevTreeIndexNodePropGet<u32> for DevTreeIndexNode<'a, 'i, 'dt> {
fn prop(&self, name: &str) -> Option<u32> {
self.props().find_map(|prop| {
if prop.name().ok()? == name {
prop.u32(0).ok()
} else {
None
}
})
}
}
impl<'a, 'i, 'dt> DevTreeIndexNodePropGet<&'a str> for DevTreeIndexNode<'a, 'i, 'dt> {
fn prop(&self, name: &str) -> Option<&'a str> {
self.props().find_map(|prop| {
if prop.name().ok()? == name {
prop.str().ok()
} else {
None
}
})
}
}
/// Iterator for physical memory regions present in the device tree
#[derive(Clone)]
pub struct FdtMemoryRegionIter<'a> {
inner: DevTreeIndexNodeSiblingIter<'a, 'a, 'a>,
address_cells: usize,
size_cells: usize,
}
/// Device tree wrapper struct
pub struct DeviceTree<'a> {
tree: DevTree<'a>,
index: DevTreeIndex<'a, 'a>,
}
impl<'a> DeviceTree<'a> {
/// Constructs a device tree wrapper from the DTB virtual address.
///
/// # Safety
///
/// The caller must ensure the validity of the address.
pub unsafe fn from_addr(virt: usize) -> Self {
let tree = DevTree::from_raw_pointer(virt as _).unwrap();
let index = DevTreeIndex::new(tree, &mut FDT_INDEX_BUFFER.0).unwrap();
Self { tree, index }
}
/// Looks up a node for a given path
pub fn node_by_path(&self, path: &str) -> Option<TNode> {
find_node(self.index.root(), path.trim_start_matches('/'))
}
/// Prints the device tree to log output
pub fn dump(&self, level: LogLevel) {
self.index.root().dump(level, 0)
}
/// Returns the total size of the device tree in memory
pub fn size(&self) -> usize {
self.tree.totalsize()
}
/// Returns the root node's `#address-cells` property, or the default value defined by the
/// specification if it's absent
pub fn address_cells(&self) -> usize {
self.index.root().address_cells()
}
/// Returns the root node's `#size-cells` property, or the default value defined by the
/// specification if it's absent
pub fn size_cells(&self) -> usize {
self.index.root().size_cells()
}
/// Returns the root node of the device tree
pub fn root(&self) -> DevTreeIndexNode {
self.index.root()
}
}
impl<'a, 'i, 'dt> DevTreeIndexNodeExt for DevTreeIndexNode<'a, 'i, 'dt> {
fn get_address_cells(&self) -> Option<usize> {
self.props()
.find(|p| p.name().unwrap_or("") == "#address-cells")
.map(|p| p.u32(0).unwrap() as usize)
}
fn get_size_cells(&self) -> Option<usize> {
self.props()
.find(|p| p.name().unwrap_or("") == "#size-cells")
.map(|p| p.u32(0).unwrap() as usize)
}
fn dump(&self, level: LogLevel, depth: usize) {
fn indent(level: LogLevel, depth: usize) {
for _ in 0..depth {
log_print_raw!(level, " ");
}
}
let node_name = self.name().unwrap();
// Don't dump these
if node_name.starts_with("virtio_mmio@") {
return;
}
indent(level, depth);
log_print_raw!(level, "{:?} {{\n", node_name);
for prop in self.props() {
indent(level, depth + 1);
let name = prop.name().unwrap_or("<???>");
log_print_raw!(level, "{name:?} = ");
match name {
"compatible" | "stdout-path" => {
log_print_raw!(level, "{:?}", prop.str().unwrap_or("<???>"))
}
_ => log_print_raw!(level, "{:x?}", prop.raw()),
}
log_print_raw!(level, "\n");
}
for child in self.children() {
child.dump(level, depth + 1);
}
indent(level, depth);
log_print_raw!(level, "}}\n");
}
}
impl<'a, 'i, 'dt> DevTreeIndexPropExt for DevTreeIndexProp<'a, 'i, 'dt> {
fn read_cell(&self, u32_offset: usize, cell_size: usize) -> Option<u64> {
match cell_size {
1 => self.u32(u32_offset).map(|x| x as u64).ok(),
2 => {
let high = self.u32(u32_offset).ok()? as u64;
let low = self.u32(u32_offset + 1).ok()? as u64;
Some((high << 32) | low)
}
_ => unimplemented!(),
}
}
fn cell1_array_item(&self, index: usize, cells: usize) -> Option<u64> {
self.read_cell(index * cells, cells)
}
fn cell2_array_item(&self, index: usize, cells0: usize, cells1: usize) -> Option<(u64, u64)> {
let u32_index = index * (cells0 + cells1);
let cell0 = self.read_cell(u32_index, cells0)?;
let cell1 = self.read_cell(u32_index + cells0, cells1)?;
Some((cell0, cell1))
}
}
impl<'a> FdtMemoryRegionIter<'a> {
/// Constructs a memory region iterator for given device tree
pub fn new(dt: &'a DeviceTree) -> Self {
let inner = dt.index.root().children();
let address_cells = dt.address_cells();
let size_cells = dt.size_cells();
Self {
inner,
address_cells,
size_cells,
}
}
}
impl Iterator for FdtMemoryRegionIter<'_> {
type Item = PhysicalMemoryRegion;
fn next(&mut self) -> Option<Self::Item> {
loop {
let Some(item) = self.inner.next() else {
break None;
};
let name = item.name().unwrap_or("");
if name.starts_with("memory@") || name == "memory" {
let reg = item
.props()
.find(|p| p.name().unwrap_or("") == "reg")
.unwrap();
let (base, size) = reg
.cell2_array_item(0, self.address_cells, self.size_cells)
.unwrap();
break Some(PhysicalMemoryRegion {
base: base as usize,
size: size as usize,
});
}
}
}
}
/// Looks up a property with given name in the node
pub fn find_prop<'a>(node: &TNode<'a>, name: &str) -> Option<TProp<'a>> {
node.props().find(|p| p.name().unwrap_or("") == name)
}
fn path_component_left(path: &str) -> (&str, &str) {
if let Some((left, right)) = path.split_once('/') {
(left, right.trim_start_matches('/'))
} else {
(path, "")
}
}
fn find_node<'a>(at: TNode<'a>, path: &str) -> Option<TNode<'a>> {
let (item, path) = path_component_left(path);
if item.is_empty() {
assert_eq!(path, "");
Some(at)
} else {
let child = at.children().find(|c| c.name().unwrap() == item)?;
if path.is_empty() {
Some(child)
} else {
find_node(child, path)
}
}
}
struct DevTreeProbe<'a> {
compatible: &'static [&'static str],
probe_func: fn(&'a DevTreeNodeInfo<'a, 'a, 'a>) -> Option<Box<dyn Device>>,
}
/// Provides information about a device tree node to device driver's "probe" function
pub struct DevTreeNodeInfo<'a, 'i, 'dt> {
/// #address-cells property of the parent bus/system
pub address_cells: usize,
/// #size-cells property of the parent bus/system
pub size_cells: usize,
/// Device tree node being probed
pub node: DevTreeIndexNode<'a, 'i, 'dt>,
}
fn iter_dt_probes<'a>() -> impl Iterator<Item = DevTreeProbe<'a>> {
extern "C" {
static __dt_probes_start: u64;
static __dt_probes_end: u64;
}
unsafe {
let base = &__dt_probes_start as *const u64;
let end = &__dt_probes_end as *const u64;
let len = (end as usize - base as usize) / (size_of::<u64>() * 3);
(0..len).map(move |i| {
let compatible_ptr = *base.add(i * 3);
let compatible_len = *base.add(i * 3 + 1);
let probe_func_ptr = *base.add(i * 3 + 2);
let compatible =
core::slice::from_raw_parts(compatible_ptr as *const &str, compatible_len as usize);
let probe_func = core::mem::transmute(probe_func_ptr);
DevTreeProbe {
compatible,
probe_func,
}
})
}
}
fn dt_match_compatible(compatible: &str) -> Option<DevTreeProbe> {
iter_dt_probes().find(|probe| probe.compatible.contains(&compatible))
}
/// "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<(&'static dyn Device, DeviceId)> {
// TODO use list, not just the first item
let Some(compatible) = dt.node.prop("compatible") else {
return None;
};
let probe = dt_match_compatible(compatible)?;
let device = Box::leak((probe.probe_func)(dt)?);
let id = register_device(device);
Some((device, id))
}
/// 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: Fn(&str, DevTreeNodeInfo) -> Result<(), Error>,
>(
address_cells: usize,
size_cells: usize,
nodes: I,
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) {
warnln!("{}: {:?}", name, error);
failed_count += 1;
}
}
if failed_count == 0 {
Ok(())
} else {
Err(failed_count)
}
}

View File

@ -4,6 +4,7 @@ use core::mem::size_of;
use abi::{error::Error, primitive_enum};
use alloc::vec::Vec;
use bitflags::bitflags;
use kernel_util::util::StaticVector;
use crate::{
debug::DebugSink,
@ -13,7 +14,6 @@ use crate::{
},
sync::IrqSafeSpinlock,
task::tasklet::TaskFlow,
util::StaticVector,
};
const CONSOLE_ROW_LEN: usize = 128;
@ -23,36 +23,31 @@ const DEFAULT_FG_COLOR: ColorAttribute = ColorAttribute::White;
const DEFAULT_BG_COLOR: ColorAttribute = ColorAttribute::Blue;
primitive_enum! {
#[allow(missing_docs)]
#[doc = "Color attribute of a console character"]
pub enum ColorAttribute: u8 {
#[doc = "..."]
Black = 0,
#[doc = "..."]
Red = 1,
#[doc = "..."]
Green = 2,
#[doc = "..."]
Yellow = 3,
#[doc = "..."]
Blue = 4,
#[doc = "..."]
Magenta = 5,
#[doc = "..."]
Cyan = 6,
#[doc = "..."]
White = 7,
}
}
bitflags! {
#[doc = "Extra attributes of a console character"]
#[derive(Clone, Copy)]
pub struct Attributes: u8 {
#[allow(missing_docs)]
const BOLD = 1 << 0;
}
}
impl ColorAttribute {
pub fn from_vt100(val: u8) -> Self {
fn from_vt100(val: u8) -> Self {
match val {
0..=7 => Self::try_from(val).unwrap(),
_ => ColorAttribute::Red,
@ -102,7 +97,7 @@ pub struct ConsoleBuffer {
height: u32,
}
pub enum EscapeState {
enum EscapeState {
Normal,
Escape,
Csi,
@ -116,7 +111,9 @@ pub struct ConsoleState {
pub cursor_col: u32,
/// Current foreground color
pub fg_color: ColorAttribute,
/// Current background color
pub bg_color: ColorAttribute,
/// Current set of attributes
pub attributes: Attributes,
esc_args: StaticVector<u32, MAX_CSI_ARGS>,
@ -177,6 +174,7 @@ impl ConsoleChar {
}
}
/// Returns the attributes of the character
#[inline]
pub fn attributes(self) -> (ColorAttribute, ColorAttribute, Attributes) {
let fg =
@ -256,8 +254,20 @@ impl ConsoleRow {
impl ConsoleBuffer {
/// Constructs a fixed-size console buffer
pub const fn fixed(rows: &'static mut [ConsoleRow], height: u32) -> Self {
Self { rows, height }
pub fn new(height: u32) -> Result<Self, Error> {
let size = size_of::<ConsoleRow>() * (height as usize);
let page_count = (size + 0xFFF) / 0x1000;
let pages = phys::alloc_pages_contiguous(page_count, PageUsage::Used)?;
let rows = unsafe {
core::slice::from_raw_parts_mut(pages.virtualize() as *mut ConsoleRow, height as usize)
};
for row in rows.iter_mut() {
row.clear(DEFAULT_BG_COLOR);
}
Ok(Self { rows, height })
}
/// Reallocates the internal buffer with a new size
@ -394,12 +404,12 @@ impl ConsoleState {
// Move back one character
b'D' => {
if self.cursor_col > 0 {
self.cursor_col = self.cursor_col - 1;
self.cursor_col -= 1;
}
}
// Manipulate display attributes
b'm' => {
if let Some(arg) = self.esc_args.get(0) {
if let Some(arg) = self.esc_args.first() {
match arg {
// Reset
0 => {

View File

@ -112,11 +112,12 @@ impl FramebufferConsole {
/// Constructs an instance of console from its framebuffer reference
pub fn from_framebuffer(
framebuffer: &'static LinearFramebuffer,
font: &'static BitmapFont<'static>,
font: Option<&'static BitmapFont<'static>>,
buffer: ConsoleBuffer,
) -> Self {
let char_width = 6;
let char_height = 12;
let font = font.unwrap_or(&bitmap_font::tamzen::FONT_7x14);
let char_width = font.width();
let char_height = font.height();
let dim = framebuffer.dimensions();
let inner = Inner {
@ -151,12 +152,6 @@ impl Inner {
text.draw(self).ok();
}
fn fill_row(&mut self, y: u32, h: u32, val: u32) {
let mut fb = unsafe { self.framebuffer.lock() };
fb.fill_rows(y, h, val);
}
fn fill_rect(&mut self, x: u32, y: u32, w: u32, h: u32, val: u32) {
let mut fb = unsafe { self.framebuffer.lock() };

View File

@ -3,8 +3,9 @@
use core::ops::{Index, IndexMut};
use abi::error::Error;
use device_api::Device;
use crate::{device::Device, mem::device::DeviceMemory, sync::IrqSafeSpinlock};
use crate::{mem::device::DeviceMemory, sync::IrqSafeSpinlock};
use super::{DisplayDevice, DisplayDimensions};
@ -76,7 +77,7 @@ impl LinearFramebuffer {
}
impl Device for LinearFramebuffer {
fn name(&self) -> &'static str {
fn display_name(&self) -> &'static str {
"Linear Framebuffer"
}
}

View File

@ -3,6 +3,8 @@
use super::Device;
pub mod console;
#[cfg(feature = "fb_console")]
pub mod fb_console;
pub mod linear_fb;

View File

@ -1,178 +1,20 @@
//! Device management and interfaces
use core::mem::size_of;
use abi::error::Error;
use alloc::boxed::Box;
use device_api::{manager::DeviceManager, Device, DeviceId};
use fdt_rs::{index::DevTreeIndexNode, prelude::PropReader};
use crate::{
arch::aarch64::devtree,
sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard},
};
use crate::sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard};
#[cfg(target_arch = "aarch64")]
pub mod devtree;
pub mod bus;
pub mod display;
pub mod power;
pub mod serial;
pub mod tty;
// pub mod display;
static DEVICE_MANAGER: IrqSafeSpinlock<DeviceManager> = IrqSafeSpinlock::new(DeviceManager::new());
/// Helper macro to return the count of expressions supplied to it
#[macro_export]
macro_rules! count {
() => (0usize);
($x:tt $($xs:tt)*) => (1usize + $crate::count!($($xs)*));
}
/// Registers a device driver for compatible device tree nodes
///
/// # Usage example
///
/// ```
/// device_tree_driver! {
/// compatible: ["arm,pl011"],
/// probe(of) => {
/// let my_device = ...; // ... extract some info about the device ...
/// Some(Box::new(my_device))
/// }
/// }
/// ```
#[macro_export]
macro_rules! device_tree_driver {
(
compatible: [$($compatible:literal),+],
probe ($node:ident) => $probe_body:block $(,)?
) => {
const __COMPATIBLE_LEN: usize = $crate::count!($($compatible )+);
static __COMPATIBLE: [&str; __COMPATIBLE_LEN] = [$($compatible),+];
fn __probe($node: &$crate::device::DevTreeNodeInfo) ->
Option<alloc::boxed::Box<dyn device_api::Device>> $probe_body
core::arch::global_asm!(r#"
.pushsection .dt_probes, "a"
.quad {compatible}
.quad {compatible_len}
.quad {probe_func}
.popsection
"#,
compatible = sym __COMPATIBLE,
compatible_len = const __COMPATIBLE_LEN,
probe_func = sym __probe
);
};
}
struct DevTreeProbe<'a> {
compatible: &'static [&'static str],
probe_func: fn(&'a DevTreeNodeInfo<'a, 'a, 'a>) -> Option<Box<dyn Device>>,
}
/// Provides information about a device tree node to device driver's "probe" function
pub struct DevTreeNodeInfo<'a, 'i, 'dt> {
/// #address-cells property of the parent bus/system
pub address_cells: usize,
/// #size-cells property of the parent bus/system
pub size_cells: usize,
/// Device tree node being probed
pub node: DevTreeIndexNode<'a, 'i, 'dt>,
}
fn iter_dt_probes<'a>() -> impl Iterator<Item = DevTreeProbe<'a>> {
extern "C" {
static __dt_probes_start: u64;
static __dt_probes_end: u64;
}
unsafe {
let base = &__dt_probes_start as *const u64;
let end = &__dt_probes_end as *const u64;
let len = (end as usize - base as usize) / (size_of::<u64>() * 3);
(0..len).map(move |i| {
let compatible_ptr = *base.add(i * 3);
let compatible_len = *base.add(i * 3 + 1);
let probe_func_ptr = *base.add(i * 3 + 2);
let compatible =
core::slice::from_raw_parts(compatible_ptr as *const &str, compatible_len as usize);
let probe_func = core::mem::transmute(probe_func_ptr);
DevTreeProbe {
compatible,
probe_func,
}
})
}
}
fn dt_match_compatible(compatible: &str) -> Option<DevTreeProbe> {
iter_dt_probes().find(|probe| probe.compatible.contains(&compatible))
}
/// "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<(&'static dyn Device, DeviceId)> {
// TODO use list, not just the first item
let Some(compatible) =
devtree::find_prop(&dt.node, "compatible").and_then(|prop| prop.str().ok())
else {
return None;
};
let probe = dt_match_compatible(compatible)?;
let device = Box::leak((probe.probe_func)(dt)?);
let id = register_device(device);
Some((device, id))
}
/// 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: Fn(&str, DevTreeNodeInfo) -> Result<(), Error>,
>(
address_cells: usize,
size_cells: usize,
nodes: I,
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) =
devtree::find_prop(&probe.node, "compatible").and_then(|prop| prop.str().ok())
else {
continue;
};
if let Err(error) = f(compatible, probe) {
warnln!("{}: {:?}", name, error);
failed_count += 1;
}
}
if failed_count == 0 {
Ok(())
} else {
Err(failed_count)
}
}
/// Adds a device to the kernel's device table and returns the ID assigned to it
pub fn register_device(device: &'static dyn Device) -> DeviceId {
debugln!("Register {:?}", device.display_name());

View File

@ -6,10 +6,8 @@ use device_api::{CpuBringupDevice, Device, ResetDevice};
use fdt_rs::prelude::PropReader;
use crate::{
arch::{
aarch64::devtree::{self},
Architecture, ArchitectureImpl, ARCHITECTURE,
},
arch::{Architecture, ArchitectureImpl, ARCHITECTURE},
device::devtree,
device_tree_driver,
};

View File

@ -1,4 +1,10 @@
//! Power-management related device drivers
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod arm_psci;
pub mod sunxi_rwdog;
}
}

View File

@ -3,19 +3,17 @@
use abi::error::Error;
use alloc::boxed::Box;
use device_api::{Device, ResetDevice};
use kernel_util::util::OneTimeInit;
use tock_registers::{
interfaces::Writeable, register_bitfields, register_structs, registers::ReadWrite,
};
use crate::{
arch::{
aarch64::devtree::{self, DevTreeIndexNodePropGet, DevTreeIndexPropExt},
Architecture, ARCHITECTURE,
},
arch::{Architecture, ARCHITECTURE},
device::devtree::{self, DevTreeIndexNodePropGet, DevTreeIndexPropExt},
device_tree_driver,
mem::device::DeviceMemoryIo,
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
register_bitfields! {

View File

@ -1,4 +1,10 @@
//! Serial device interfaces
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(target_arch = "aarch64")] {
pub mod pl011;
pub mod sunxi_uart;
}
}

View File

@ -1,11 +1,8 @@
//! ARM PL011 driver
use abi::{error::Error, io::DeviceRequest};
use alloc::boxed::Box;
use device_api::{
interrupt::{InterruptHandler, IrqNumber},
serial::SerialDevice,
Device,
};
use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device};
use kernel_util::util::OneTimeInit;
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@ -14,17 +11,16 @@ use tock_registers::{
use vfs::CharDevice;
use crate::{
arch::{
aarch64::devtree::{self, DevTreeIndexPropExt},
Architecture, ARCHITECTURE,
},
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
debug::{self, DebugSink, LogLevel},
device::tty::{CharRing, TtyDevice},
device::{
devtree::{self, DevTreeIndexPropExt},
tty::{CharRing, TtyDevice},
},
device_tree_driver,
fs::devfs::{self, CharDeviceType},
mem::device::DeviceMemoryIo,
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
register_bitfields! {

View File

@ -2,11 +2,8 @@
use abi::{error::Error, io::DeviceRequest};
use alloc::boxed::Box;
use device_api::{
interrupt::{InterruptHandler, IrqNumber},
serial::SerialDevice,
Device,
};
use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device};
use kernel_util::util::OneTimeInit;
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@ -15,17 +12,16 @@ use tock_registers::{
use vfs::CharDevice;
use crate::{
arch::{
aarch64::devtree::{self, DevTreeIndexPropExt},
Architecture, ARCHITECTURE,
},
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
debug::{self, DebugSink, LogLevel},
device::tty::{CharRing, TtyDevice},
device::{
devtree::{self, DevTreeIndexPropExt},
tty::{CharRing, TtyDevice},
},
device_tree_driver,
fs::devfs::{self, CharDeviceType},
mem::device::DeviceMemoryIo,
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
register_bitfields! {

View File

@ -1,13 +0,0 @@
//! Time-providing device interfaces
use core::time::Duration;
use abi::error::Error;
use super::Device;
/// Interface for devices capable of providing some notion of time
pub trait TimestampSource: Device {
/// Returns current time signalled by the device. The time may not be a "real" time and instead
/// is assumed to be monotonically increasing.
fn timestamp(&self) -> Result<Duration, Error>;
}

View File

@ -14,13 +14,13 @@ use crate::{
#[cfg(feature = "fb_console")]
pub mod combined {
//! Combined console + keyboard terminal device
use abi::{error::Error, io::DeviceRequest};
use device_api::{input::KeyboardConsumer, serial::SerialDevice};
use vfs::CharDevice;
use crate::device::{
display::{console::DisplayConsole, fb_console::FramebufferConsole},
input::KeyboardDevice,
serial::SerialDevice,
Device,
};
@ -29,21 +29,15 @@ pub mod combined {
// TODO rewrite this
/// Helper device to combine a display and a keyboard input into a single terminal
pub struct CombinedTerminal {
#[allow(dead_code)]
input: &'static dyn KeyboardDevice,
output: &'static dyn DisplayConsole,
output: &'static (dyn DisplayConsole + Sync + 'static),
input_ring: CharRing<16>,
}
impl CombinedTerminal {
/// Create a combined terminal device from a keyboard and console output devices
pub fn new(
input: &'static dyn KeyboardDevice,
output: &'static FramebufferConsole,
) -> Self {
pub fn new(output: &'static FramebufferConsole) -> Self {
Self {
input,
output,
input_ring: CharRing::new(),
}
@ -56,11 +50,14 @@ pub mod combined {
}
}
impl SerialDevice for CombinedTerminal {
fn receive(&self, _blocking: bool) -> Result<u8, Error> {
todo!()
impl KeyboardConsumer for CombinedTerminal {
fn handle_character(&self, data: u8) -> Result<(), Error> {
self.recv_byte(data);
Ok(())
}
}
impl SerialDevice for CombinedTerminal {
fn send(&self, byte: u8) -> Result<(), Error> {
self.output.write_char(byte);
Ok(())
@ -68,7 +65,7 @@ pub mod combined {
}
impl Device for CombinedTerminal {
fn name(&self) -> &'static str {
fn display_name(&self) -> &'static str {
"Combined terminal device"
}
}

View File

@ -6,12 +6,11 @@ use abi::{
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use alloc::{boxed::Box, format, string::String};
use kernel_util::util::OneTimeInit;
use vfs::{
CharDevice, CharDeviceWrapper, Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE,
};
use crate::util::OneTimeInit;
/// Describes the kind of a character device
#[derive(Debug)]
pub enum CharDeviceType {
@ -24,16 +23,11 @@ pub enum CharDeviceType {
struct DevfsDirectory;
impl VnodeImpl for DevfsDirectory {
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
fn open(&self, _node: &VnodeRef, _opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
Ok(DIR_POSITION_FROM_CACHE)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
mode: FileMode::default_dir(),

View File

@ -2,17 +2,15 @@
use core::ptr::NonNull;
use kernel_util::util::OneTimeInit;
use memfs::block::{self, BlockAllocator};
use vfs::VnodeRef;
use yggdrasil_abi::{error::Error, io::MountOptions};
use crate::{
mem::{
use crate::mem::{
self,
phys::{self, PageUsage},
ConvertAddress,
},
util::OneTimeInit,
};
pub mod devfs;

View File

@ -30,8 +30,8 @@ pub fn kinit() {
{
use core::time::Duration;
use device::display::console::task_update_consoles;
use task::tasklet;
use crate::device::display::console::task_update_consoles;
use crate::task::tasklet;
tasklet::add_periodic(
"update-console",

View File

@ -9,7 +9,8 @@
arbitrary_self_types,
const_mut_refs,
let_chains,
linked_list_cursors
linked_list_cursors,
rustc_private
)]
#![allow(clippy::new_without_default, clippy::fn_to_numeric_cast)]
#![warn(missing_docs)]
@ -17,7 +18,7 @@
#![no_main]
use sync::SpinFence;
use task::{context::Cpu, spawn_kernel_closure};
use task::spawn_kernel_closure;
use crate::{
arch::{Architecture, ArchitectureImpl, ARCHITECTURE},
@ -27,6 +28,7 @@ use crate::{
extern crate yggdrasil_abi as abi;
extern crate alloc;
extern crate compiler_builtins;
#[macro_use]
pub mod debug;
@ -42,7 +44,6 @@ pub mod proc;
pub mod sync;
pub mod syscall;
pub mod task;
pub mod util;
static CPU_INIT_FENCE: SpinFence = SpinFence::new();
@ -75,7 +76,7 @@ pub fn kernel_main() -> ! {
ARCHITECTURE.start_application_processors();
}
Cpu::init_ipi_queues();
// Cpu::init_ipi_queues();
// Wait until all APs initialize
CPU_INIT_FENCE.signal();

View File

@ -286,70 +286,20 @@ pub fn validate_user_region(
#[no_mangle]
unsafe extern "C" fn memcpy(p0: *mut c_void, p1: *const c_void, len: usize) -> *mut c_void {
let mut offset = 0;
while offset < len {
let c = (p1 as *const u8).add(offset).read_volatile();
(p0 as *mut u8).add(offset).write_volatile(c);
offset += 1;
}
p0
compiler_builtins::mem::memcpy(p0 as _, p1 as _, len) as _
}
#[no_mangle]
unsafe extern "C" fn memcmp(p0: *const c_void, p1: *const c_void, len: usize) -> i32 {
let mut offset = 0;
if len == 0 {
return 0;
}
while offset < len {
let c0 = (p0 as *const u8).add(offset).read_volatile();
let c1 = (p1 as *const u8).add(offset).read_volatile();
#[allow(clippy::comparison_chain)]
if c0 > c1 {
return (c0 - c1) as i32;
} else if c0 < c1 {
return -((c1 - c0) as i32);
}
offset += 1;
}
0
compiler_builtins::mem::memcmp(p0 as _, p1 as _, len)
}
#[no_mangle]
unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, len: usize) -> *mut c_void {
if dst as usize == src as usize {
return dst;
}
if (src.add(len) as usize) <= (dst as usize) || (dst.add(len) as usize) <= (src as usize) {
return memcpy(dst, src, len);
}
if (dst as usize) < (src as usize) {
let a = src as usize - dst as usize;
memcpy(dst, src, a);
memcpy(src as *mut _, src.add(a), len - a);
} else {
let a = dst as usize - src as usize;
memcpy(dst.add(a), dst, len - a);
memcpy(dst, src, a);
}
dst
compiler_builtins::mem::memmove(dst as _, src as _, len) as _
}
#[no_mangle]
unsafe extern "C" fn memset(dst: *mut c_void, val: i32, len: usize) -> *mut c_void {
let mut offset = 0;
while offset < len {
(dst as *mut u8).add(offset).write_volatile(val as u8);
offset += 1;
}
dst
compiler_builtins::mem::memset(dst as _, val, len) as _
}

View File

@ -2,6 +2,7 @@
use core::{iter::StepBy, mem::size_of, ops::Range};
use abi::error::Error;
use kernel_util::util::OneTimeInit;
use crate::{
debug::LogLevel,
@ -10,7 +11,6 @@ use crate::{
ConvertAddress, /*, KERNEL_PHYS_BASE */
},
sync::IrqSafeSpinlock,
util::OneTimeInit,
};
use self::manager::PhysicalMemoryManager;

View File

@ -1,6 +1,6 @@
//! Utilities for handling reserved memory regions
use crate::util::StaticVector;
use kernel_util::util::StaticVector;
use super::PhysicalMemoryRegion;

View File

@ -11,6 +11,7 @@ use abi::{
};
use alloc::{collections::VecDeque, rc::Rc, string::String};
use atomic_enum::atomic_enum;
use kernel_util::util::OneTimeInit;
use vfs::VnodeRef;
use crate::{
@ -22,7 +23,6 @@ use crate::{
},
sync::{IrqGuard, IrqSafeSpinlock},
task::context::TaskContextImpl,
util::OneTimeInit,
};
use super::{context::TaskFrame, sched::CpuQueue, Cpu, ProcessId, TaskContext, PROCESSES};

View File

@ -3,12 +3,12 @@
// use aarch64_cpu::registers::CNTPCT_EL0;
use alloc::{collections::VecDeque, rc::Rc, vec::Vec};
use cfg_if::cfg_if;
use kernel_util::util::OneTimeInit;
use crate::{
// arch::aarch64::{context::TaskContext, cpu::Cpu},
arch::{Architecture, ArchitectureImpl},
sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard},
util::OneTimeInit,
};
use super::{