Compare commits

..

1 Commits

Author SHA1 Message Date
alnyan 5ee2e0c5ab strace: rewrite strace with cross 2025-08-11 23:55:55 +03:00
85 changed files with 2783 additions and 73454 deletions
Generated
-20
View File
@@ -2872,25 +2872,6 @@ dependencies = [
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_usb_dwc2"
version = "0.1.0"
dependencies = [
"async-trait",
"atomic_enum",
"bytemuck",
"device-api",
"device-tree",
"futures-util",
"libk",
"libk-mm",
"libk-util",
"log",
"tock-registers",
"ygg_driver_usb",
"yggdrasil-abi",
]
[[package]]
name = "ygg_driver_usb_xhci"
version = "0.1.0"
@@ -3048,7 +3029,6 @@ dependencies = [
"ygg_driver_nvme",
"ygg_driver_pci",
"ygg_driver_usb",
"ygg_driver_usb_dwc2",
"ygg_driver_usb_xhci",
"ygg_driver_virtio_blk",
"ygg_driver_virtio_gpu",
-1
View File
@@ -7,7 +7,6 @@ exclude = [
"toolchain",
"userspace/dynload-program",
"userspace/lib/ygglibc",
"userspace",
"toolchain-c"
]
members = [
Binary file not shown.
+1327 -514
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -58,7 +58,6 @@ device-tree.workspace = true
kernel-arch-aarch64.workspace = true
ygg_driver_bsp_arm.path = "driver/bsp/arm"
ygg_driver_bsp_bcm283x.path = "driver/bsp/bcm283x"
ygg_driver_usb_dwc2.path = "driver/usb/dwc2"
[target.'cfg(target_arch = "riscv64")'.dependencies]
device-tree.workspace = true
-8
View File
@@ -4,8 +4,6 @@ const EXT_HSM: u64 = 0x48534D;
const EXT_TIME: u64 = 0x54494D45;
const EXT_DBCN: u64 = 0x4442434E;
const EXT_SPI: u64 = 0x735049;
const EXT_SYSTEM_SHUTDOWN: u64 = 0x53525354;
const EXT_SYSTEM_SHUTDOWN_LEGACY: u64 = 0x08;
primitive_enum! {
pub enum Status: i64 {
@@ -110,9 +108,3 @@ pub fn sbi_debug_console_write_byte(byte: u8) {
pub fn sbi_set_timer(next_event: u64) {
unsafe { sbi_do_call(EXT_TIME, 0x00, next_event, 0, 0, 0, 0, 0) }.ok();
}
pub fn sbi_system_shutdown() -> ! {
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN_LEGACY, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
unreachable!()
}
+8 -13
View File
@@ -1,8 +1,8 @@
#![feature(allocator_api, never_type)]
#![feature(allocator_api)]
#![no_std]
use acpi::AcpiTables;
use acpi_system::{AcpiInterruptMethod, AcpiSleepState, AcpiSystem};
use acpi_system::{AcpiInterruptMethod, AcpiSystem};
use alloc::boxed::Box;
use libk::error::Error;
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
@@ -45,17 +45,6 @@ pub fn get_pci_route(
.ok()
}
pub fn power_off() -> Result<!, Error> {
let system = ACPI_SYSTEM.get();
unsafe {
system.lock().enter_sleep_state(AcpiSleepState::S5).ok();
loop {
core::arch::asm!("cli; hlt");
}
}
}
/// Initializes ACPI management
pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<(), Error> {
// NOTE mostly broken for real HW
@@ -78,6 +67,12 @@ pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<()
// // 6. Do something with the devices
// // 7. Actually enter the S5 state
// unsafe {
// PLATFORM
// .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown)
// .unwrap();
// }
// SHUTDOWN_FENCE.signal();
// SHUTDOWN_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire));
-1
View File
@@ -4,5 +4,4 @@
extern crate alloc;
mod pl011;
mod pl031;
mod pl061;
+7 -5
View File
@@ -1,12 +1,12 @@
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@@ -68,7 +68,7 @@ struct Pl011Inner {
pub struct Pl011 {
inner: OneTimeInit<Arc<Terminal<Pl011Inner>>>,
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
}
impl Io {
@@ -164,12 +164,14 @@ impl Device for Pl011 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
{
let io = self.inner.get().output().io.lock();
io.regs.IMSC.modify(IMSC::RXIM::SET);
}
self.irq.enable()?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
-66
View File
@@ -1,66 +0,0 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => RTCDR: ReadOnly<u32>),
(0x04 => RTCMR: ReadWrite<u32>),
(0x08 => RTCLR: ReadWrite<u32>),
(0x0C => RTCCR: ReadWrite<u32>),
(0x10 => RTCIMSC: ReadWrite<u32>),
(0x14 => RTCRIS: ReadOnly<u32>),
(0x18 => RTCMIS: ReadOnly<u32>),
(0x1C => RTCICR: WriteOnly<u32>),
(0x20 => @END),
}
}
struct Pl031 {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Pl031 {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
Ok(regs.RTCDR.get() as _)
}
}
impl Device for Pl031 {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"ARM PL031 RTC"
}
}
device_tree_driver! {
compatible: ["arm,pl031"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Pl031 { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
+6 -5
View File
@@ -8,7 +8,7 @@ use device_api::{
GpioController, GpioInterruptEvent, GpioInterruptMode, GpioPinLevel, PinHandle,
SinglePinDirection,
},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
driver::{
@@ -17,7 +17,7 @@ use device_tree::{
},
DeviceTreePropertyRead, TProp,
};
use libk::event::signal_gpio_event;
use libk::{device::external_interrupt_controller, event::signal_gpio_event};
use libk_mm::device::DeviceMemoryIo;
use libk_util::{bit::BitField, sync::IrqSafeSpinlock};
use tock_registers::{
@@ -50,7 +50,7 @@ register_structs! {
struct Pl061 {
#[allow(unused)]
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
irq: IrqHandle,
irq: FullIrq,
clocks: Vec<ClockHandle>,
resets: Vec<ResetHandle>,
gpio_events: [AtomicU64; 8],
@@ -69,8 +69,9 @@ impl Device for Pl061 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
+6 -5
View File
@@ -2,12 +2,12 @@ use alloc::sync::Arc;
use device_api::{
clock::ClockHandle,
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@@ -61,7 +61,7 @@ struct Inner {
/// Broadcom 283x mini-UART driver
pub struct Bcm2835AuxUart {
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
clock: ClockHandle,
inner: OneTimeInit<Arc<Terminal<Inner>>>,
}
@@ -171,8 +171,9 @@ impl Device for Bcm2835AuxUart {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
let inner = self.inner.get().output();
let regs = inner.regs.lock();
+6 -4
View File
@@ -2,7 +2,7 @@ use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
gpio::{GpioController, GpioInterruptEvent, PinHandle},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
driver::{
@@ -11,6 +11,7 @@ use device_tree::{
},
DeviceTreePropertyRead, TProp,
};
use libk::device::external_interrupt_controller;
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
@@ -68,7 +69,7 @@ register_structs! {
struct Bcm2711Gpio {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
#[allow(unused)]
irqs: [IrqHandle; 2],
irqs: [FullIrq; 2],
}
impl Regs {
@@ -141,9 +142,10 @@ impl Device for Bcm2711Gpio {
regs.configure_pin_interrupts(pin, false, false, false, false);
}
let intc = external_interrupt_controller()?;
for irq in self.irqs.iter() {
irq.register(self.clone())?;
irq.enable()?;
intc.register_irq(irq.irq, irq.options, self.clone())?;
intc.enable_irq(irq.irq)?;
}
Ok(())
@@ -1,70 +0,0 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite},
};
use yggdrasil_abi::time::NANOSECONDS_IN_SECOND;
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => TIME_LOW: ReadOnly<u32>),
(0x04 => TIME_HIGH: ReadOnly<u32>),
(0x08 => ALARM_LOW: ReadWrite<u32>),
(0x0C => ALARM_HIGH: ReadWrite<u32>),
(0x10 => IRQ_ENABLED: ReadWrite<u32>),
(0x14 => CLEAR_ALARM: ReadWrite<u32>),
(0x18 => ALARM_STATUS: ReadOnly<u32>),
(0x1C => CLEAR_INTERRUPT: ReadWrite<u32>),
(0x20 => @END),
}
}
struct Rtc {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Rtc {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
let low = regs.TIME_LOW.get();
let high = regs.TIME_HIGH.get();
let t = ((high as u64) << 32) | (low as u64);
Ok(t / NANOSECONDS_IN_SECOND)
}
}
impl Device for Rtc {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"Google Goldfish RTC"
}
}
device_tree_driver! {
compatible: ["google,goldfish-rtc"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Rtc { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
-1
View File
@@ -3,5 +3,4 @@
extern crate alloc;
mod goldfish_rtc;
mod plic;
+4 -5
View File
@@ -2,8 +2,8 @@ use alloc::{sync::Arc, vec::Vec};
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
IrqHandle, IrqOptions, IrqVector,
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, Irq, IrqOptions, IrqVector,
},
};
use device_tree::{
@@ -261,12 +261,11 @@ impl Device for Plic {
}
impl DeviceTreeInterruptController for Plic {
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle> {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
let num = property.read_cell(offset, 1)?;
Some(IrqHandle {
Some(FullIrq {
irq: Irq::External(num as _),
options: IrqOptions::default(),
intc: self.clone(),
})
}
+2 -3
View File
@@ -1,10 +1,9 @@
use core::{any::Any, fmt, mem::MaybeUninit};
use alloc::{sync::Arc, vec};
use alloc::sync::Arc;
use libk::{
block,
error::Error,
task::sync::AsyncMutex,
vfs::{
CommonImpl, CreateInfo, DirectoryImpl, DirectoryOpenPosition, Filename, Metadata, Node,
NodeFlags, NodeRef,
@@ -282,10 +281,10 @@ impl DirectoryNode {
} else {
let file = FileNode {
fs: self.fs.clone(),
cluster,
size_bytes: size,
parent: Some(self.cluster),
metadata,
cluster_chain_cache: AsyncMutex::new(vec![cluster]),
};
Ok(Node::regular(
+32 -17
View File
@@ -1,6 +1,6 @@
use core::any::Any;
use alloc::{sync::Arc, vec::Vec};
use alloc::{sync::Arc, vec, vec::Vec};
use libk::{
block,
error::Error,
@@ -13,22 +13,28 @@ use crate::{data::ClusterNumber, Fat32Fs};
pub struct FileNode {
pub(crate) fs: Arc<Fat32Fs>,
pub(crate) cluster: ClusterNumber,
pub(crate) size_bytes: u32,
pub(crate) metadata: Metadata,
// Will be used when metadata needs to be updated
#[allow(unused)]
pub(crate) parent: Option<ClusterNumber>,
pub(crate) cluster_chain_cache: AsyncMutex<Vec<ClusterNumber>>,
}
impl FileNode {
async fn fetch_cluster_number(
&self,
file: &FileNode,
cluster_index: usize,
) -> Result<ClusterNumber, Error> {
let mut chain = self.cluster_chain_cache.lock().await;
// TODO use a "sliding window" to minimize memory usage when working with large files?
struct OpenedFile {
cluster_chain: AsyncMutex<Vec<ClusterNumber>>,
}
impl OpenedFile {
fn new(first_cluster: ClusterNumber) -> Self {
Self {
cluster_chain: AsyncMutex::new(vec![first_cluster]),
}
}
async fn seek(&self, file: &FileNode, cluster_index: usize) -> Result<ClusterNumber, Error> {
let mut chain = self.cluster_chain.lock().await;
if cluster_index >= chain.len() {
let last = *chain.last().unwrap();
file.fs
@@ -41,8 +47,15 @@ impl FileNode {
Ok(chain[cluster_index])
}
}
async fn read_inner(&self, mut pos: u64, buffer: &mut [u8]) -> Result<usize, Error> {
impl FileNode {
async fn read_inner(
&self,
instance: &OpenedFile,
mut pos: u64,
buffer: &mut [u8],
) -> Result<usize, Error> {
if pos >= self.size_bytes as u64 {
return Ok(0);
}
@@ -60,9 +73,7 @@ impl FileNode {
let offset_in_sector = (pos % bps) as usize;
let amount = rem.min(bps as usize - offset_in_sector);
let cluster = self
.fetch_cluster_number(self, cluster_index as usize)
.await?;
let cluster = instance.seek(self, cluster_index as usize).await?;
self.fs
.with_cluster_sector(cluster, sector_in_cluster, |data| {
@@ -108,7 +119,8 @@ impl RegularImpl for FileNode {
if opts.contains_any(OpenOptions::TRUNCATE | OpenOptions::APPEND | OpenOptions::WRITE) {
return Err(Error::ReadOnly);
}
Ok((0, None))
let instance = Arc::new(OpenedFile::new(self.cluster));
Ok((0, Some(instance)))
}
fn close(&self, _node: &NodeRef, _instance: Option<&InstanceData>) -> Result<(), Error> {
@@ -118,11 +130,14 @@ impl RegularImpl for FileNode {
fn read(
&self,
_node: &NodeRef,
_instance: Option<&InstanceData>,
instance: Option<&InstanceData>,
pos: u64,
buf: &mut [u8],
) -> Result<usize, Error> {
block!(self.read_inner(pos, buf).await)?
let instance = instance
.and_then(|p| p.downcast_ref::<OpenedFile>())
.ok_or(Error::InvalidFile)?;
block!(self.read_inner(instance, pos, buf).await)?
}
fn write(
+12 -33
View File
@@ -20,7 +20,6 @@ use yggdrasil_abi::{
error::Error,
io::{FileMode, FileType, GroupId, UserId},
path::Path,
time::SystemTime,
};
use crate::tar::TarIterator;
@@ -76,7 +75,6 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
path: &Path,
create: bool,
mode: FileMode,
mtime: SystemTime,
) -> Result<NodeRef, Error> {
let access = unsafe { AccessToken::authorized() };
if path.is_empty() {
@@ -99,18 +97,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
}
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
let metadata = Metadata {
uid: UserId::root(),
gid: GroupId::root(),
atime: mtime,
ctime: mtime,
mode,
mtime,
inode: Some(ino),
block_size: 512,
block_count: 0,
};
let node = DirectoryNode::<A>::new(self.clone(), metadata);
let node = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(mode, ino));
at.add_child(filename, node.clone())?;
node
@@ -125,7 +112,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
Ok(node)
} else {
assert!(node.is_directory());
self.make_path(&node, rest, create, mode, mtime)
self.make_path(&node, rest, create, mode)
}
}
@@ -133,22 +120,16 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
let kind = hdr.node_kind();
let mode = usize::from(&hdr.mode);
let mode = FileMode::new(0o777 & (mode as u32));
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
let metadata = Metadata {
uid: UserId::root(),
gid: GroupId::root(),
atime: mtime,
ctime: mtime,
mode,
mtime,
inode: Some(ino),
block_size: 512,
block_count: usize::from(&hdr.size).div_ceil(512) as u64,
};
match kind {
FileType::File => Ok(FileNode::<A>::new(self.clone(), metadata)),
FileType::Directory => Ok(DirectoryNode::<A>::new(self.clone(), metadata)),
FileType::File => Ok(FileNode::<A>::new(
self.clone(),
Metadata::now_root(mode, ino),
)),
FileType::Directory => Ok(DirectoryNode::<A>::new(
self.clone(),
Metadata::now_root(mode, ino),
)),
FileType::Symlink => {
let target = hdr.symlink_target()?;
Ok(fixed_path_symlink(target))
@@ -168,10 +149,9 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
};
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let (dirname, filename) = path.split_right();
let parent = self.make_path(&root, dirname, true, FileMode::new(0o755), mtime)?;
let parent = self.make_path(&root, dirname, true, FileMode::new(0o755))?;
let node = self.create_node_initial(hdr)?;
let filename = Filename::new(filename)?;
@@ -184,9 +164,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
panic!("Unreachable");
};
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let node = self.make_path(&root, path, false, FileMode::empty(), mtime)?;
let node = self.make_path(&root, path, false, FileMode::empty())?;
assert_eq!(node.ty(), hdr.node_kind());
let uid = unsafe { UserId::from_raw(usize::from(&hdr.uid) as u32) };
+1 -1
View File
@@ -23,7 +23,7 @@ pub(crate) struct TarEntry {
pub uid: OctalField<8>,
pub gid: OctalField<8>,
pub size: OctalField<12>,
pub mtime: OctalField<12>,
_mtime: OctalField<12>,
_checksum: OctalField<8>,
type_: u8,
link_name: TarString<100>,
+7 -4
View File
@@ -8,13 +8,14 @@ use device_api::{
clock::{ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
dma::DmaAllocator,
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{
device_tree_driver, util::read_mac_address, InitSequence, Node, ProbeContext,
};
use futures_util::task::AtomicWaker;
use libk::{
device::external_interrupt_controller,
dma::DmaBuffer,
error::Error,
task::runtime::{self, psleep, pwait},
@@ -67,7 +68,7 @@ struct Stmmac {
rst_stmmaceth: ResetHandle,
rst_ahb: ResetHandle,
irq: IrqHandle,
irq: FullIrq,
softirq_events: BitmapEvent<AtomicWaker>,
inner: OneTimeInit<Inner>,
@@ -183,7 +184,9 @@ impl Device for Stmmac {
}
let dma = self.dma.init(cx.dma_allocator.clone());
self.irq.register(self.clone())?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
let tx_ring_capacity = 32;
let rx_ring_capacity = 32;
@@ -347,7 +350,7 @@ impl Device for Stmmac {
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
self.iface_id.init(iface.id());
self.irq.enable()?;
intc.enable_irq(self.irq.irq)?;
let p = self.clone();
runtime::spawn(async move { p.softirq().await })?;
-21
View File
@@ -1,21 +0,0 @@
[package]
name = "ygg_driver_usb_dwc2"
version = "0.1.0"
edition = "2024"
[dependencies]
yggdrasil-abi = { path = "../../../../lib/abi" }
device-api = { path = "../../../lib/device-api", features = ["derive"] }
ygg_driver_usb = { path = "../../bus/usb" }
device-tree = { path = "../../../lib/device-tree" }
libk-util = { path = "../../../libk/libk-util" }
libk-mm = { path = "../../../libk/libk-mm" }
libk = { path = "../../../libk" }
async-trait.workspace = true
log.workspace = true
atomic_enum.workspace = true
tock-registers.workspace = true
bytemuck.workspace = true
futures-util.workspace = true
-222
View File
@@ -1,222 +0,0 @@
#![no_std]
use core::{
sync::atomic::{AtomicBool, AtomicU32},
time::Duration,
};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqVector},
};
use futures_util::task::AtomicWaker;
use libk::{error::Error, task::runtime};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
LocalRegisterCopy,
};
use yggdrasil_abi::bitflags;
use crate::{
regs::{PortSpeed, Regs},
vendor::Dwc2Impl,
};
extern crate alloc;
mod regs;
mod vendor;
pub struct Dwc2<H: Dwc2Impl> {
imp: H,
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
name: Arc<str>,
channel_bitmask: AtomicU32,
port_event_mask: BitmapEvent<AtomicWaker>,
}
impl<H: Dwc2Impl + 'static> Dwc2<H> {
pub unsafe fn new<N: Into<Arc<str>>>(
imp: H,
base: PhysicalAddress,
name: N,
) -> Result<Self, Error> {
let name = name.into();
let regs = IrqSafeSpinlock::new(unsafe { DeviceMemoryIo::map(base, Default::default()) }?);
Ok(Self {
imp,
regs,
name,
channel_bitmask: AtomicU32::new(0),
port_event_mask: BitmapEvent::new(AtomicWaker::new()),
})
}
fn signal_events(&self, channels: u16, ports: u32) {
self.port_event_mask
.signal(((channels as u64) << 32) | (ports as u64));
}
async fn setup_port(self: Arc<Self>, speed: PortSpeed) -> Result<(), Error> {
log::info!("{}: setup port", self.name);
todo!()
}
async fn wait_for_port_event(&self) -> LocalRegisterCopy<u32, regs::HPRT::Register> {
LocalRegisterCopy::new(self.port_event_mask.wait_mask(0x2A).await as u32)
}
async fn wait_for_channel_events(&self) -> u16 {
(self.port_event_mask.wait_mask(0xFFFF00000000).await >> 32) as u16
}
async fn wait_for_device(&self) -> PortSpeed {
let hprt = self.regs.lock().HPRT.extract();
// If already connected, begin init, if not, wait for connect change
if !hprt.matches_all(regs::HPRT::PCSTS::SET) {
loop {
let event = self.wait_for_port_event().await;
if event.matches_all(regs::HPRT::PCDET::SET) {
log::info!("{}: port connection detected", self.name);
break;
} else {
log::warn!("{}: unhandled port event {:#x}", self.name, event.get());
}
}
}
log::info!("{}: port connected", self.name);
// Reset the port
{
let regs = self.regs.lock();
regs.HPRT.modify(regs::HPRT::PRST::SET);
}
runtime::sleep(Duration::from_millis(10)).await;
// Clear the reset
{
let regs = self.regs.lock();
regs.HPRT.modify(regs::HPRT::PRST::CLEAR);
}
// Wait for port enable status
loop {
let event = self.wait_for_port_event().await;
if event.matches_all(regs::HPRT::PENA::SET) {
log::info!("{}: port enabled", self.name);
break;
}
if event.matches_all(regs::HPRT::PCSTS::CLEAR) {
todo!("Handle port disconnect");
}
}
let regs = self.regs.lock();
match regs.HPRT.read_as_enum(regs::HPRT::PSPD) {
Some(regs::HPRT::PSPD::Value::LowSpeed) => PortSpeed::LowSpeed,
Some(regs::HPRT::PSPD::Value::FullSpeed) => PortSpeed::FullSpeed,
Some(regs::HPRT::PSPD::Value::HighSpeed) => PortSpeed::HighSpeed,
_ => todo!(),
}
}
async fn softirq(self: Arc<Self>) -> Result<(), Error> {
loop {
// 4-9
let speed = self.wait_for_device().await;
// 10. HFIR setup for PHY clk TODO
// 11. Configure FSLPCS based on step 9 TODO
// 12. GRXFSIZ to configure Rx FIFO size
// 13. HNPTXFSIZ to configure non-periodic Tx FIFO
// 14. HPTXFSIZ to configure periodic Tx FIFO
if let Err(error) = self.clone().setup_port(speed).await {
log::error!("{}: port error {:?}", self.name, error);
}
}
}
async fn setup(self: Arc<Self>) -> Result<(), Error> {
log::info!("{}: init", self.name);
let regs = self.regs.lock();
regs.soft_reset(Duration::from_secs(1)).await?;
// Common setup
regs.GAHBCFG
.write(regs::GAHBCFG::GINTMSK::SET + regs::GAHBCFG::DMAEN::SET);
// GUSBCTL
// TODO HNP/SRP capability?
// TODO OTG_FS/OTG_HS timeout calibration
// TODO USB turnaround time
regs.GINTMSK.write(
regs::GINTMSK::OTGINT::SET
+ regs::GINTMSK::MMISM::SET
+ regs::GINTMSK::USBRST::SET
+ regs::GINTMSK::ENUMDNEM::SET
+ regs::GINTMSK::OEPINT::SET
+ regs::GINTMSK::IEPINT::SET
// + regs::GINTMSK::PRTIM::SET
+ regs::GINTMSK::DISCINT::SET,
);
let mode = if regs.GINTSTS.matches_all(regs::GINTSTS::CMOD::Host) {
"host"
} else {
log::warn!("TODO: device mode setup");
"device"
};
log::info!("{}: operating in {} mode", self.name, mode);
// Host mode setup
// 1. Enable HPRTINT
regs.GINTMSK.modify(regs::GINTMSK::PRTIM::SET);
// 2. Setup FS host
regs.HCFG
.write(regs::HCFG::FSLSS::CLEAR + regs::HCFG::FSLSPCS.val(1));
// 3. Drive Vbus on the USB
regs.HPRT.modify(regs::HPRT::PPWR::SET);
// 4. Wait for PCDET interrupt on HPRT0
runtime::spawn(self.clone().softirq())?;
Ok(())
}
}
impl<H: Dwc2Impl + 'static> Device for Dwc2<H> {
unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
unsafe { self.imp.initialize_host_early(self.clone()) }?;
runtime::spawn(self.clone().setup())?;
Ok(())
}
fn display_name(&self) -> &str {
&self.name
}
}
impl<H: Dwc2Impl + 'static> InterruptHandler for Dwc2<H> {
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
let regs = self.regs.lock();
let gintsts = regs.take_interrupt();
let hprt = if gintsts.matches_all(regs::GINTSTS::HPRTINT::SET) {
regs.take_port_status().get()
} else {
0
};
if hprt != 0 {
self.signal_events(0, hprt);
}
true
}
}
-292
View File
@@ -1,292 +0,0 @@
use core::time::Duration;
use libk::{error::Error, task::runtime, time};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
registers::ReadWrite,
LocalRegisterCopy,
};
register_bitfields! {
u32,
pub GAHBCFG [
PTXFELVL OFFSET(8) NUMBITS(1) [],
TXFELVL OFFSET(7) NUMBITS(1) [],
DMAEN OFFSET(5) NUMBITS(1) [],
HBSTLEN OFFSET(1) NUMBITS(4) [],
GINTMSK OFFSET(0) NUMBITS(1) [],
],
pub GUSBCFG [
FDMOD OFFSET(30) NUMBITS(1) [],
FHMOD OFFSET(29) NUMBITS(1) [],
ULPIIPD OFFSET(25) NUMBITS(1) [],
PTCI OFFSET(24) NUMBITS(1) [],
PCCI OFFSET(23) NUMBITS(1) [],
TSDPS OFFSET(22) NUMBITS(1) [],
ULPIEVBUSI OFFSET(21) NUMBITS(1) [],
ULPIEVBUSD OFFSET(20) NUMBITS(1) [],
ULPICSM OFFSET(19) NUMBITS(1) [],
ULPIAR OFFSET(18) NUMBITS(1) [],
ULPIFSLS OFFSET(17) NUMBITS(1) [],
PHYLPC OFFSET(15) NUMBITS(1) [],
TRDT OFFSET(10) NUMBITS(4) [],
HNPCAP OFFSET(9) NUMBITS(1) [],
SRPCAP OFFSET(8) NUMBITS(1) [],
PHYSEL OFFSET(6) NUMBITS(1) [],
TOCAL OFFSET(0) NUMBITS(3) [],
],
pub GRSTCTL [
AHBIDL OFFSET(31) NUMBITS(1) [],
DMAREQ OFFSET(30) NUMBITS(1) [],
TXFNUM OFFSET(6) NUMBITS(5) [],
TXFFLSH OFFSET(5) NUMBITS(1) [],
RXFFLSH OFFSET(4) NUMBITS(1) [],
FCRST OFFSET(2) NUMBITS(1) [],
PSRST OFFSET(1) NUMBITS(1) [],
CSRST OFFSET(0) NUMBITS(1) [],
],
pub GINTSTS [
WKUPINT OFFSET(31) NUMBITS(1) [],
SRQINT OFFSET(30) NUMBITS(1) [],
DISCINT OFFSET(29) NUMBITS(1) [],
CIDSCHG OFFSET(28) NUMBITS(1) [],
LPMINT OFFSET(27) NUMBITS(1) [],
PTXFE OFFSET(26) NUMBITS(1) [],
HCINT OFFSET(25) NUMBITS(1) [],
HPRTINT OFFSET(24) NUMBITS(1) [],
RSTDET OFFSET(23) NUMBITS(1) [],
DATAFSUSP OFFSET(22) NUMBITS(1) [],
IPXFR OFFSET(21) NUMBITS(1) [],
IISOIXFR OFFSET(20) NUMBITS(1) [],
OEPINT OFFSET(19) NUMBITS(1) [],
IEPINT OFFSET(18) NUMBITS(1) [],
EOPF OFFSET(15) NUMBITS(1) [],
ISOODRP OFFSET(14) NUMBITS(1) [],
ENUMDNE OFFSET(13) NUMBITS(1) [],
USBRST OFFSET(12) NUMBITS(1) [],
USBSUSP OFFSET(11) NUMBITS(1) [],
ESUSP OFFSET(10) NUMBITS(1) [],
GONAKEFF OFFSET(7) NUMBITS(1) [],
GINAKEFF OFFSET(6) NUMBITS(1) [],
NPTXFE OFFSET(5) NUMBITS(1) [],
RXFLVL OFFSET(4) NUMBITS(1) [],
SOF OFFSET(3) NUMBITS(1) [],
OTGINT OFFSET(2) NUMBITS(1) [],
MMIS OFFSET(1) NUMBITS(1) [],
CMOD OFFSET(0) NUMBITS(1) [
Device = 0,
Host = 1
],
],
pub GINTMSK [
WUIM OFFSET(31) NUMBITS(1) [],
SRQIM OFFSET(30) NUMBITS(1) [],
DISCINT OFFSET(29) NUMBITS(1) [],
CIDSCHGM OFFSET(28) NUMBITS(1) [],
LPMINTM OFFSET(27) NUMBITS(1) [],
PTXFEM OFFSET(26) NUMBITS(1) [],
HCIM OFFSET(25) NUMBITS(1) [],
PRTIM OFFSET(24) NUMBITS(1) [],
RSTDETM OFFSET(23) NUMBITS(1) [],
FSUSPM OFFSET(22) NUMBITS(1) [],
IPXFRM OFFSET(21) NUMBITS(1) [],
IISOIXFRM OFFSET(20) NUMBITS(1) [],
OEPINT OFFSET(19) NUMBITS(1) [],
IEPINT OFFSET(18) NUMBITS(1) [],
EOPFM OFFSET(15) NUMBITS(1) [],
ISOODRPM OFFSET(14) NUMBITS(1) [],
ENUMDNEM OFFSET(13) NUMBITS(1) [],
USBRST OFFSET(12) NUMBITS(1) [],
USBSUSPM OFFSET(11) NUMBITS(1) [],
ESUSPM OFFSET(10) NUMBITS(1) [],
GONAKEFFM OFFSET(7) NUMBITS(1) [],
GINAKEFFM OFFSET(6) NUMBITS(1) [],
NPTXFEM OFFSET(5) NUMBITS(1) [],
RXFLVLM OFFSET(4) NUMBITS(1) [],
SOFM OFFSET(3) NUMBITS(1) [],
OTGINT OFFSET(2) NUMBITS(1) [],
MMISM OFFSET(1) NUMBITS(1) [],
],
pub HCFG [
FSLSS OFFSET(2) NUMBITS(1) [],
FSLSPCS OFFSET(0) NUMBITS(2) [],
],
pub HPRT [
PSPD OFFSET(17) NUMBITS(2) [
HighSpeed = 0,
FullSpeed = 1,
LowSpeed = 2,
],
PTCTL OFFSET(13) NUMBITS(4) [],
PPWR OFFSET(12) NUMBITS(1) [],
PLSTS OFFSET(10) NUMBITS(2) [],
PRST OFFSET(8) NUMBITS(1) [],
PSUSP OFFSET(7) NUMBITS(1) [],
PRES OFFSET(6) NUMBITS(1) [],
POCCHNG OFFSET(5) NUMBITS(1) [],
POCA OFFSET(4) NUMBITS(1) [],
PENCHNG OFFSET(3) NUMBITS(1) [],
PENA OFFSET(2) NUMBITS(1) [],
PCDET OFFSET(1) NUMBITS(1) [],
PCSTS OFFSET(0) NUMBITS(1) [],
],
pub HCCHARx [
CHENA OFFSET(31) NUMBITS(1) [],
CHDIS OFFSET(30) NUMBITS(1) [],
ODDFRM OFFSET(29) NUMBITS(1) [],
DAD OFFSET(22) NUMBITS(7) [],
MCNT OFFSET(20) NUMBITS(2) [],
EPTYP OFFSET(18) NUMBITS(2) [
Control = 0,
Isochronous = 1,
Bulk = 2,
Interrupt = 3
],
LSDEV OFFSET(17) NUMBITS(1) [],
EPDIR OFFSET(15) NUMBITS(1) [
Out = 0,
In = 1
],
EPNUM OFFSET(11) NUMBITS(4) [],
MPSIZ OFFSET(0) NUMBITS(11) [],
],
pub HCSPLTx [
SPLITEN OFFSET(31) NUMBITS(1) [],
COMPLSPLT OFFSET(16) NUMBITS(1) [],
XACTPOS OFFSET(14) NUMBITS(2) [
Mid = 0,
End = 1,
Begin = 2,
All = 3,
],
HUBADDR OFFSET(7) NUMBITS(7) [],
PRTADDR OFFSET(0) NUMBITS(7) [],
],
pub HCINTx [
DTERR OFFSET(10) NUMBITS(1) [],
FRMOR OFFSET(9) NUMBITS(1) [],
BBERR OFFSET(8) NUMBITS(1) [],
TXERR OFFSET(7) NUMBITS(1) [],
NYET OFFSET(6) NUMBITS(1) [],
ACK OFFSET(5) NUMBITS(1) [],
NAK OFFSET(4) NUMBITS(1) [],
STALL OFFSET(3) NUMBITS(1) [],
AHBERR OFFSET(2) NUMBITS(1) [],
CHH OFFSET(1) NUMBITS(1) [],
XFRC OFFSET(0) NUMBITS(1) [],
],
pub HCTSIZx [
DPID OFFSET(29) NUMBITS(2) [
DATA0 = 0,
DATA2 = 1,
DATA1 = 2,
SETUP = 3
],
PKTCNT OFFSET(19) NUMBITS(10) [],
XFRSIZ OFFSET(0) NUMBITS(19) []
],
}
register_structs! {
#[allow(non_snake_case)]
pub HostChannelRegs {
(0x00 => pub HCCHARx: ReadWrite<u32, HCCHARx::Register>),
(0x04 => pub HCSPLTx: ReadWrite<u32, HCSPLTx::Register>),
(0x08 => pub HCINTx: ReadWrite<u32, HCINTx::Register>),
(0x0C => pub HCINTMSKx: ReadWrite<u32, HCINTx::Register>),
(0x10 => pub HCTSIZx: ReadWrite<u32, HCTSIZx::Register>),
(0x14 => pub HCDMAx: ReadWrite<u32>),
(0x18 => _0),
(0x20 => @END),
}
}
register_structs! {
#[allow(non_snake_case)]
pub Regs {
(0x000 => pub GOTGCTL: ReadWrite<u32>),
(0x004 => pub GOTGINT: ReadWrite<u32>),
(0x008 => pub GAHBCFG: ReadWrite<u32, GAHBCFG::Register>),
(0x00C => pub GUSBCFG: ReadWrite<u32, GUSBCFG::Register>),
(0x010 => pub GRSTCTL: ReadWrite<u32, GRSTCTL::Register>),
(0x014 => pub GINTSTS: ReadWrite<u32, GINTSTS::Register>),
(0x018 => pub GINTMSK: ReadWrite<u32, GINTMSK::Register>),
(0x01C => pub GRXSTSR: ReadWrite<u32>),
(0x020 => pub GRXSTSP: ReadWrite<u32>),
(0x024 => pub GRXFSIZ: ReadWrite<u32>),
(0x028 => pub HNPTXFSIZ: ReadWrite<u32>),
(0x02C => pub HNPTXSTS: ReadWrite<u32>),
(0x030 => _0),
(0x038 => pub GCCFG: ReadWrite<u32>),
(0x03C => pub CID: ReadWrite<u32>),
(0x040 => _1),
(0x054 => pub GLPMCFG: ReadWrite<u32>),
(0x058 => _2),
(0x100 => pub HPTXFSIZ: ReadWrite<u32>),
(0x104 => pub DIEPTXF_N: [ReadWrite<u32>; 8]),
(0x124 => _3),
(0x400 => pub HCFG: ReadWrite<u32, HCFG::Register>),
(0x404 => pub HFIR: ReadWrite<u32>),
(0x408 => pub HFNUM: ReadWrite<u32>),
(0x40C => _4),
(0x410 => pub HPTXSTS: ReadWrite<u32>),
(0x414 => pub HAINT: ReadWrite<u32>),
(0x418 => pub HAINTMSK: ReadWrite<u32>),
(0x41C => _5),
(0x440 => pub HPRT: ReadWrite<u32, HPRT::Register>),
(0x444 => _6),
(0x500 => pub CHANNELx: [HostChannelRegs; 16]),
(0x700 => _7),
(0x800 => _8),
(0xF00 => @END),
}
}
unsafe impl Send for Regs {}
unsafe impl Sync for Regs {}
pub enum PortSpeed {
LowSpeed,
FullSpeed,
HighSpeed,
}
impl Regs {
pub async fn soft_reset(&self, timeout: Duration) -> Result<(), Error> {
self.GRSTCTL.modify(GRSTCTL::CSRST::SET);
let deadline = time::monotonic_time() + timeout;
let mut timeout = true;
while time::monotonic_time() < deadline {
if self.GRSTCTL.matches_all(GRSTCTL::CSRST::CLEAR) {
timeout = false;
break;
}
runtime::sleep(Duration::from_millis(20)).await;
}
if timeout {
return Err(Error::TimedOut);
}
// The spec wants the OS to wait for at least 3 PHY clocks
runtime::sleep(Duration::from_millis(100)).await;
assert!(self.GRSTCTL.matches_all(GRSTCTL::AHBIDL::SET));
Ok(())
}
pub fn take_interrupt(&self) -> LocalRegisterCopy<u32, GINTSTS::Register> {
let intsts = self.GINTSTS.extract();
self.GINTSTS.set(intsts.get());
intsts
}
pub fn take_port_status(&self) -> LocalRegisterCopy<u32, HPRT::Register> {
let hprt = self.HPRT.extract();
self.HPRT.set(hprt.get());
hprt
}
}
-65
View File
@@ -1,65 +0,0 @@
use alloc::sync::Arc;
use device_api::{clock::ClockHandle, device::Device, interrupt::IrqHandle};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::error::Error;
use libk_mm::device::DeviceMemoryIo;
use crate::{regs::Regs, Dwc2};
pub trait Dwc2Impl: Send + Sync + Sized {
unsafe fn initialize_host_early(&self, dwc2: Arc<Dwc2<Self>>) -> Result<(), Error>;
async unsafe fn initialize_host(
&self,
dwc2: Arc<Dwc2<Self>>,
regs: &DeviceMemoryIo<'_, Regs>,
) -> Result<(), Error>;
}
pub struct Bcm2835Usb {
clk_otg: ClockHandle,
irq: IrqHandle,
}
impl Dwc2Impl for Bcm2835Usb {
unsafe fn initialize_host_early(&self, dwc2: Arc<Dwc2<Self>>) -> Result<(), Error> {
// TODO PHY setup
self.irq.register(dwc2)?;
self.irq.enable()?;
self.clk_otg.enable()?;
Ok(())
}
async unsafe fn initialize_host(
&self,
dwc2: Arc<Dwc2<Self>>,
regs: &DeviceMemoryIo<'_, Regs>,
) -> Result<(), Error> {
todo!()
}
}
device_tree_driver! {
compatible: ["brcm,bcm2835-usb"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0).unwrap();
let clk_otg = node.named_clock("otg").unwrap();
let irq = node.interrupt(0).unwrap();
let name = node.name()?;
node.dump();
let imp = Bcm2835Usb {
clk_otg,
irq
};
let dwc2 = unsafe { Dwc2::new(imp, base, name) }
.inspect_err(|e| log::error!("{name}: setup error {e:?}"))
.ok()?;
Some(Arc::new(dwc2))
}
}
}
+2 -13
View File
@@ -3,11 +3,10 @@ use yggdrasil_abi::error::Error;
use crate::device::Device;
#[derive(Clone)]
pub struct IrqHandle {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FullIrq {
pub irq: Irq,
pub options: IrqOptions,
pub intc: Arc<dyn ExternalInterruptController>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -155,16 +154,6 @@ pub struct FixedInterruptTable<const N: usize> {
rows: [Option<Arc<dyn InterruptHandler>>; N],
}
impl IrqHandle {
pub fn register(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error> {
self.intc.register_irq(self.irq, self.options, handler)
}
pub fn enable(&self) -> Result<(), Error> {
self.intc.enable_irq(self.irq)
}
}
impl<const N: usize> FixedInterruptTable<N> {
pub const fn new() -> Self {
Self {
@@ -3,7 +3,7 @@ use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, ResetHandle},
gpio::PinHandle,
interrupt::IrqHandle,
interrupt::FullIrq,
};
use fdt_rs::spec::Phandle;
@@ -83,14 +83,14 @@ pub fn map_interrupt_at(
interrupt_controller: &Arc<Node>,
property: &TProp,
offset: usize,
) -> Option<IrqHandle> {
) -> Option<FullIrq> {
let interrupt_controller = interrupt_controller.interrupt_controller.try_get()?;
interrupt_controller.clone().map_interrupt(property, offset)
interrupt_controller.map_interrupt(property, offset)
}
/// Same as [map_interrupt_at], but uses a phandle to address the `interrupt-controller` node
/// and a scaled `index`.
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<IrqHandle> {
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<FullIrq> {
let interrupt_controller = lookup_phandle(phandle, true)?;
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
map_interrupt_at(&interrupt_controller, property, index * interrupt_cells)
+2 -2
View File
@@ -7,7 +7,7 @@ use device_api::{
clock::{ClockHandle, ResetHandle},
device::Device,
gpio::PinHandle,
interrupt::{ExternalInterruptController, IrqHandle},
interrupt::{ExternalInterruptController, FullIrq},
};
use libk::error::Error;
@@ -25,7 +25,7 @@ pub trait Driver: Sync {
pub trait DeviceTreeInterruptController {
/// Reads interrupt information from `property` at given `offset` and maps it to
/// the interrupt used by the controller
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle>;
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq>;
/// Returns the [ExternalInterruptController] implementor of this node
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController>;
+3 -3
View File
@@ -10,7 +10,7 @@ use device_api::{
clock::{ClockController, ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
gpio::PinHandle,
interrupt::{ExternalInterruptController, IrqHandle, MessageInterruptController},
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
};
use fdt_rs::spec::Phandle;
use libk::dma::DummyDmaAllocator;
@@ -410,7 +410,7 @@ impl Node {
/// Reads interrupt information from `interrupts[index]` property, mapped by the node's
/// `interrupt-parent`.
pub fn interrupt(&self, index: usize) -> Option<IrqHandle> {
pub fn interrupt(&self, index: usize) -> Option<FullIrq> {
let interrupts = self.property("interrupts")?;
let phandle = self.interrupt_parent?;
map_interrupt(phandle, &interrupts, index)
@@ -418,7 +418,7 @@ impl Node {
/// Same as [Node::interrupt], but allows specifying other property to read the information
/// from.
pub fn interrupt_from(&self, property: &TProp, index: usize) -> Option<IrqHandle> {
pub fn interrupt_from(&self, property: &TProp, index: usize) -> Option<FullIrq> {
let phandle = self.interrupt_parent?;
map_interrupt(phandle, property, index)
}
+3 -2
View File
@@ -3,7 +3,7 @@
use alloc::sync::Arc;
use device_api::{
gpio::{GpioPinConfig, GpioPinLevel, InputPinBias, OutputPinBias},
interrupt::{IrqHandle, MessageInterruptController},
interrupt::{FullIrq, MessageInterruptController},
};
use fdt_rs::prelude::PropReader;
use yggdrasil_abi::net::MacAddress;
@@ -44,6 +44,7 @@ pub struct GenericPinctrlConfig {
}
/// Represents an entry in a PCIe-controller's `interrupt-map` field
#[derive(Debug)]
pub struct PcieInterruptEntry {
/// PCI address bus
pub bus: u8,
@@ -56,7 +57,7 @@ pub struct PcieInterruptEntry {
/// Destination interrupt controller
pub interrupt_controller: Arc<Node>,
/// Destination IRQ options
pub irq: IrqHandle,
pub irq: FullIrq,
}
/// Represents a single PCI address (Requester ID for a MSI(-x))
-15
View File
@@ -204,21 +204,6 @@ impl<N: EventNotify> BitmapEvent<N> {
self.notify.notify_all();
}
pub async fn wait_mask(&self, mask: u64) -> u64 {
let not_mask = !mask;
poll_fn(|cx| {
let state = self.value.fetch_and(not_mask, Ordering::AcqRel);
if state & mask != 0 {
self.notify.unsubscribe(cx.waker());
Poll::Ready(state)
} else {
self.notify.subscribe(cx.waker());
Poll::Pending
}
})
.await
}
pub async fn wait(&self) -> u64 {
poll_fn(|cx| {
let state = self.value.swap(0, Ordering::AcqRel);
-1
View File
@@ -5,7 +5,6 @@ use object::KObject;
use crate::vfs::NodeRef;
pub mod attribute;
pub mod nodes;
pub mod object;
static ROOT: OneTimeInit<NodeRef> = OneTimeInit::new();
-52
View File
@@ -1,52 +0,0 @@
use core::{
marker::PhantomData,
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::{format, string::String, sync::Arc};
use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error;
use crate::fs::sysfs::{
attribute::{StringAttribute, StringAttributeOps},
device,
object::KObject,
};
pub trait SysfsRtcNode: Send + Sync + 'static {
fn read(&self) -> Result<u64, Error>;
}
static RTC_NODES: AtomicUsize = AtomicUsize::new(0);
pub fn add_rtc_node<N: SysfsRtcNode>(node: Arc<N>) {
struct Time<N>(PhantomData<N>);
impl<N: SysfsRtcNode> StringAttributeOps for Time<N> {
type Data = Arc<N>;
const NAME: &'static str = "time";
fn read(state: &Self::Data) -> Result<String, Error> {
let time = state.read()?;
Ok(format!("{time}"))
}
}
static RTC_OBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
let rtc_object = RTC_OBJECT.or_init_with(|| {
let device_object = device().unwrap();
let rtc_object = KObject::new(());
device_object.add_object("rtc", rtc_object.clone()).ok();
rtc_object
});
let rtc_node = KObject::new(node);
rtc_node
.add_attribute(StringAttribute::from(Time(PhantomData)))
.ok();
let index = RTC_NODES.fetch_add(1, Ordering::AcqRel);
let name = format!("rtc{index}");
rtc_object.add_object(name, rtc_node).ok();
}
+8 -1
View File
@@ -350,6 +350,7 @@ impl Thread {
if debug.tracer.is_some() {
let timestamp = monotonic_time();
debug.store_state(frame);
// log::info!("TRACE {payload:?}");
self.events.trace.write(TraceEvent {
suspend,
timestamp,
@@ -513,7 +514,11 @@ impl Thread {
/// Returns `true` if the thread is a tracee of given process
pub fn is_tracee_of(&self, pid: ProcessId) -> bool {
self.debug.lock().tracer == Some(pid)
{
let tracer = self.debug.lock().tracer;
// log::info!("{:?}'s tracer: {:?}", self.id, tracer);
tracer == Some(pid)
}
}
pub fn attach_trace(&self, tracer: ProcessId) -> Result<(), Error> {
@@ -577,11 +582,13 @@ impl Thread {
DebugControl::Detach => todo!(),
DebugControl::Resume => {
let single_step = debug::Resume::load_request(input)?;
// log::info!("Resume single_step={single_step}");
self.resume(single_step);
debug::Resume::store_response(&(), buffer)
}
DebugControl::SetTraceFlags => {
let flags = debug::SetTraceFlags::load_request(buffer)?;
// log::info!("SetTraceFlags {flags:?}");
self.set_trace_flags(flags);
debug::SetTraceFlags::store_response(&(), buffer)
}
-1
View File
@@ -310,7 +310,6 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
}
fn irq_common() {
// TODO some concept of "root" interrupt controller
external_interrupt_controller()
.unwrap()
.handle_pending_irqs();
+54 -52
View File
@@ -8,9 +8,9 @@ use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable,
IpiDeliveryTarget, IpiMessage, Irq, IrqHandle, IrqLevel, IrqOptions, IrqTrigger, IrqVector,
LocalInterruptController,
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
IrqVector, LocalInterruptController,
},
};
use device_tree::{
@@ -23,7 +23,7 @@ use libk_mm::{
address::PhysicalAddress,
device::{DeviceMemoryIo, RawDeviceMemoryMapping},
};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use self::{gicc::Gicc, gicd::Gicd};
@@ -41,13 +41,13 @@ pub mod gicv2m;
/// ARM Generic Interrupt Controller v2
pub struct Gic {
gicc: Gicc,
gicd: Gicd,
gicc: OneTimeInit<Gicc>,
gicd: OneTimeInit<Gicd>,
gicd_base: PhysicalAddress,
gicc_base: PhysicalAddress,
table: IrqSafeRwLock<FixedInterruptTable<MAX_IRQ>>,
}
unsafe impl Sync for Gic {}
/// Per-CPU GIC information
pub struct GicPerCpu {}
@@ -59,8 +59,32 @@ impl Device for Gic {
}
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
log::debug!(
"Init GIC: gicd={:#x}, gicc={:#x}",
self.gicd_base,
self.gicc_base
);
let gicd_mmio = Arc::new(RawDeviceMemoryMapping::map(
self.gicd_base.into_u64(),
0x1000,
Default::default(),
)?);
let gicd_mmio_shared = DeviceMemoryIo::from_raw(gicd_mmio.clone())?;
let gicd_mmio_banked = DeviceMemoryIo::from_raw(gicd_mmio)?;
let gicc_mmio = DeviceMemoryIo::map(self.gicc_base, Default::default())?;
let gicd = Gicd::new(gicd_mmio_shared, gicd_mmio_banked);
let gicc = Gicc::new(gicc_mmio);
gicd.init();
gicc.init();
self.gicd.init(gicd);
self.gicc.init(gicc);
register_external_interrupt_controller(self.clone());
AArch64::set_gic(self.clone());
Ok(())
}
}
@@ -73,6 +97,7 @@ impl ExternalInterruptController for Gic {
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
let mut table = self.table.write();
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + GIC_SPI_START,
@@ -87,7 +112,7 @@ impl ExternalInterruptController for Gic {
options.level
);
if index >= GIC_SPI_START as usize {
self.gicd.configure_irq(index, options);
gicd.configure_irq(index, options);
}
table.insert(index, handler)?;
@@ -95,27 +120,29 @@ impl ExternalInterruptController for Gic {
}
fn enable_irq(&self, irq: Irq) -> Result<(), Error> {
let gicd = self.gicd.get();
let index = match irq {
Irq::External(i) => i + GIC_SPI_START,
Irq::Private(i) => i + GIC_PPI_START,
} as usize;
log::debug!("Enable irq{index} ({irq:?})");
self.gicd.enable_irq(index);
gicd.enable_irq(index);
Ok(())
}
fn handle_pending_irqs(&self) {
let irq_number = self.gicc.pending_irq_number();
let gicc = self.gicc.get();
let irq_number = gicc.pending_irq_number();
if irq_number >= MAX_IRQ {
return;
}
self.gicc.clear_irq(irq_number);
gicc.clear_irq(irq_number);
if irq_number == IPI_VECTOR as usize {
let ipi = Cpu::local().get_ipi();
AArch64::handle_ipi(ipi);
return;
// TODO pop entry
crate::panic::panic_secondary();
}
if irq_number < GIC_PPI_START as usize {
@@ -163,20 +190,20 @@ impl LocalInterruptController for Gic {
barrier::isb(barrier::SY);
unsafe {
self.gicd.set_sgir(target, IPI_VECTOR);
self.gicd.get().set_sgir(target, IPI_VECTOR);
}
Ok(())
}
unsafe fn init_ap(&self) -> Result<(), Error> {
self.gicc.init();
self.gicc.get().init();
Ok(())
}
}
impl DeviceTreeInterruptController for Gic {
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle> {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
// IRQ_TYPE_NONE - 0
// IRQ_TYPE_EDGE_RISING - 1
// IRQ_TYPE_EDGE_FALLING - 2
@@ -202,10 +229,9 @@ impl DeviceTreeInterruptController for Gic {
_ => return None,
};
Some(IrqHandle {
Some(FullIrq {
irq,
options: IrqOptions { trigger, level },
intc: self.clone(),
})
}
@@ -220,34 +246,14 @@ impl Gic {
/// # Safety
///
/// The caller must ensure the addresses actually point to the GIC components.
pub unsafe fn new(
gicd_base: PhysicalAddress,
gicc_base: PhysicalAddress,
) -> Result<Self, Error> {
log::debug!("Init GIC: gicd={:#x}, gicc={:#x}", gicd_base, gicc_base);
let gicd_mmio = Arc::new(RawDeviceMemoryMapping::map(
gicd_base.into_u64(),
0x1000,
Default::default(),
)?);
let gicd_mmio_shared = DeviceMemoryIo::from_raw(gicd_mmio.clone())?;
let gicd_mmio_banked = DeviceMemoryIo::from_raw(gicd_mmio)?;
let gicc_mmio = DeviceMemoryIo::map(gicc_base, Default::default())?;
let gicd = Gicd::new(gicd_mmio_shared, gicd_mmio_banked);
let gicc = Gicc::new(gicc_mmio);
gicd.init();
gicc.init();
// self.gicd.init(gicd);
// self.gicc.init(gicc);
Ok(Self {
gicd,
gicc,
pub unsafe fn new(gicd_base: PhysicalAddress, gicc_base: PhysicalAddress) -> Self {
Self {
gicc: OneTimeInit::new(),
gicd: OneTimeInit::new(),
gicd_base,
gicc_base,
table: IrqSafeRwLock::new(FixedInterruptTable::new()),
})
}
}
}
@@ -268,11 +274,7 @@ device_tree_driver! {
let gicd_base = PhysicalAddress::from_u64(gicd_range.start);
let gicc_base = PhysicalAddress::from_u64(gicc_range.start);
let gic = Arc::new(unsafe {
Gic::new(gicd_base, gicc_base)
.inspect_err(|e| log::error!("GIC probe/init error: {e:?}"))
.ok()?
});
let gic = Arc::new(unsafe { Gic::new(gicd_base, gicc_base) });
// Register device-tree interrupt controller
node.make_interrupt_controller(gic.clone());
+3 -54
View File
@@ -5,15 +5,14 @@ use core::sync::atomic::{self, Ordering};
use aarch64_cpu::registers::{CNTP_CTL_EL0, CNTP_TVAL_EL0};
use alloc::sync::Arc;
use device_api::{
interrupt::{IpiDeliveryTarget, IpiMessage, Irq, LocalInterruptController},
interrupt::{Irq, LocalInterruptController},
ResetDevice,
};
use device_tree::{
driver::{unflatten_device_tree, InitSequence},
DeviceTree, DeviceTreeNodeExt,
};
use kernel_arch::Architecture;
use kernel_arch_aarch64::{mem, ArchitectureImpl, PerCpuData, CPU_COUNT};
use kernel_arch_aarch64::{mem, ArchitectureImpl, PerCpuData};
use libk::{arch::Cpu, config, debug, device::external_interrupt_controller, error::Error};
use libk_mm::{
address::PhysicalAddress,
@@ -21,7 +20,7 @@ use libk_mm::{
pointer::PhysicalRef,
table::EntryLevelExt,
};
use libk_util::{sync::SpinFence, OneTimeInit};
use libk_util::OneTimeInit;
use tock_registers::interfaces::Writeable;
use ygg_driver_pci::PciBusManager;
@@ -29,7 +28,6 @@ use crate::{
arch::{aarch64::gic::Gic, Platform},
device::{power::arm_psci::Psci, MACHINE_NAME},
fs::{Initrd, INITRD_DATA},
panic,
util::call_init_array,
};
@@ -70,8 +68,6 @@ impl<const SIZE: usize> BootStack<SIZE> {
}
}
static SHUTDOWN_FENCE: SpinFence = SpinFence::new();
impl Platform for AArch64 {
unsafe fn start_application_processors(&self) {
if let Some(compatible) = self.machine_compatible.try_get() {
@@ -100,18 +96,6 @@ impl Platform for AArch64 {
psci.reset()
}
}
unsafe fn power_off(&self) -> Result<!, Error> {
Self::halt_aps()?;
if let Some(psci) = self.psci.try_get() {
log::info!("Powering off");
psci.power_off()
} else {
log::warn!("No power off method, halting");
ArchitectureImpl::halt();
}
}
}
impl AArch64 {
@@ -119,41 +103,6 @@ impl AArch64 {
GIC.init(gic);
}
fn handle_ipi(ipi: Option<IpiMessage>) {
let Some(ipi) = ipi else {
log::warn!("Spurious IPI received, assuming panic");
panic::panic_secondary();
};
match ipi {
IpiMessage::Panic => panic::panic_secondary(),
IpiMessage::Shutdown => Self::secondary_halt_handler(),
}
}
fn secondary_halt_handler() {
log::info!("CPU halted");
SHUTDOWN_FENCE.signal();
ArchitectureImpl::halt();
}
unsafe fn halt_aps() -> Result<(), Error> {
let ap_count = CPU_COUNT.load(Ordering::Acquire) - 1;
if ap_count > 0 {
if let Some(gic) = GIC.try_get() {
gic.send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown)?;
SHUTDOWN_FENCE.wait_all(ap_count);
Ok(())
} else {
log::warn!("No way to handle secondary CPUs");
Err(Error::NotImplemented)
}
} else {
Ok(())
}
}
#[inline(never)]
unsafe fn init_memory_management(
&'static self,
+8 -6
View File
@@ -7,16 +7,16 @@ use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use kernel_arch::task::Scheduler;
use libk::{arch::Cpu, task::runtime, time};
use libk::{arch::Cpu, device::external_interrupt_controller, task::runtime, time};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
/// ARM Generic Timer driver
pub struct ArmTimer {
irq: IrqHandle,
irq: FullIrq,
}
/// ARM timer tick interval (in some time units?)
@@ -63,12 +63,14 @@ impl Device for ArmTimer {
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
log::info!("ARM Generic Timer frequency={}Hz", CNTFRQ_EL0.get());
self.irq.register(self.clone())?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
CNTP_CTL_EL0.modify(CNTP_CTL_EL0::IMASK::CLEAR);
CNTP_TVAL_EL0.set(TICK_INTERVAL);
self.irq.enable()?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
@@ -80,7 +82,7 @@ impl ArmTimer {
/// # Safety
///
/// The caller must ensure the function has not been called before.
pub const unsafe fn new(irq: IrqHandle) -> Self {
pub const unsafe fn new(irq: FullIrq) -> Self {
Self { irq }
}
}
-14
View File
@@ -1,6 +1,5 @@
//! Provides architecture/platform-specific implementation details
use abi::error::Error;
use kernel_arch::{Architecture, ArchitectureImpl};
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
@@ -52,19 +51,6 @@ pub trait Platform {
}
}
/// Performs full system powerdown.
///
/// # Safety
///
/// The caller must ensure it is actually safe to power down, i.e. no critical processes will be
/// aborted and no data will be lost.
unsafe fn power_off(&self) -> Result<!, Error> {
ArchitectureImpl::set_interrupt_mask(true);
loop {
ArchitectureImpl::wait_for_interrupt();
}
}
// /// Adds a reset device to the system
// fn register_reset_device(&self, reset: Arc<dyn ResetDevice>) -> Result<(), Error> {
// Err(Error::NotImplemented)
+1 -5
View File
@@ -11,7 +11,7 @@ use kernel_arch::{Architecture, ArchitectureImpl};
use kernel_arch_riscv64::{
mem,
registers::{SIE, SSTATUS},
sbi, PerCpuData,
PerCpuData,
};
use libk::{arch::Cpu, config};
use libk_mm::{
@@ -51,10 +51,6 @@ impl Platform for Riscv64 {
ArchitectureImpl::halt();
}
unsafe fn power_off(&self) -> Result<!, Error> {
sbi::sbi_system_shutdown()
}
unsafe fn start_application_processors(&self) {
// TODO asymmetric systems with different hart types are not yet supported.
// e.g., in JH7110 there're two different types of cores
+73 -20
View File
@@ -1,11 +1,18 @@
use abi::error::Error;
use alloc::sync::Arc;
use device_api::device::Device;
use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch::{Architecture, ArchitectureImpl};
use kernel_arch_x86::intrinsics::{io_wait, IoPort, IoPortAccess};
use libk::fs::sysfs::{self, nodes::SysfsRtcNode};
use kernel_arch_x86::{
intrinsics::{io_wait, IoPort, IoPortAccess},
ISA_IRQ_OFFSET,
};
use libk::{device::external_interrupt_controller, time};
use libk_util::sync::IrqSafeSpinlock;
const NMI_DISABLE: u8 = 1 << 7;
const CMOS_REG_SEC: u8 = 0x00;
const CMOS_REG_MIN: u8 = 0x02;
const CMOS_REG_HOUR: u8 = 0x04;
@@ -13,8 +20,13 @@ const CMOS_REG_DAY: u8 = 0x07;
const CMOS_REG_MON: u8 = 0x08;
const CMOS_REG_YEAR: u8 = 0x09;
const CMOS_REG_STATUS_A: u8 = 0x0A;
const CMOS_REG_STATUS_B: u8 = 0x0B;
const CMOS_REG_STATUS_C: u8 = 0x0C;
const STATUS_A_UPDATE_IN_PROGRESS: u8 = 1 << 7;
// Refresh every 4 ticks (every 2s)
const REFRESH_INTERVAL: u32 = 4;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct DateTime {
seconds: u8,
@@ -28,18 +40,14 @@ struct DateTime {
struct Inner {
command: IoPort<u8>,
data: IoPort<u8>,
counter: u32,
last_timestamp: Option<DateTime>,
}
pub struct Rtc {
inner: IrqSafeSpinlock<Inner>,
}
fn bcd_to_dec(x: u8) -> u8 {
let a = (x >> 4) & 0xF;
let b = x & 0xF;
a * 10 + b
}
impl Inner {
fn read_date_time(&mut self) -> DateTime {
self.wait_for_update();
@@ -63,12 +71,12 @@ impl Inner {
}
fn try_read_time(&mut self) -> DateTime {
let seconds = bcd_to_dec(self.read_reg(CMOS_REG_SEC));
let minutes = bcd_to_dec(self.read_reg(CMOS_REG_MIN));
let hours = bcd_to_dec(self.read_reg(CMOS_REG_HOUR));
let day_of_month = bcd_to_dec(self.read_reg(CMOS_REG_DAY));
let month = bcd_to_dec(self.read_reg(CMOS_REG_MON));
let year = bcd_to_dec(self.read_reg(CMOS_REG_YEAR));
let seconds = self.read_reg(CMOS_REG_SEC);
let minutes = self.read_reg(CMOS_REG_MIN);
let hours = self.read_reg(CMOS_REG_HOUR);
let day_of_month = self.read_reg(CMOS_REG_DAY);
let month = self.read_reg(CMOS_REG_MON);
let year = self.read_reg(CMOS_REG_YEAR);
DateTime {
seconds,
minutes,
@@ -91,16 +99,59 @@ impl Inner {
}
value
}
fn write_reg(&mut self, reg: u8, value: u8) {
assert!(ArchitectureImpl::interrupt_mask());
self.command.write(reg);
for _ in 0..10 {
io_wait();
}
self.data.write(value);
for _ in 0..10 {
io_wait();
}
}
fn setup_irq(&mut self) {
let rate = 15; // freq = 2Hz
let old_a = self.read_reg(CMOS_REG_STATUS_A | NMI_DISABLE);
let old_b = self.read_reg(CMOS_REG_STATUS_B | NMI_DISABLE);
let new_a = (old_a & 0xF0) | rate;
let new_b = old_b | (1 << 6) | (1 << 2) | (1 << 1);
self.write_reg(CMOS_REG_STATUS_A | NMI_DISABLE, new_a);
self.write_reg(CMOS_REG_STATUS_B | NMI_DISABLE, new_b);
}
}
impl SysfsRtcNode for Rtc {
fn read(&self) -> Result<u64, Error> {
let time = self.inner.lock().read_date_time();
Ok(time.to_seconds())
impl InterruptHandler for Rtc {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let mut inner = self.inner.lock();
if inner.counter == 0 {
let time = inner.read_date_time();
inner.last_timestamp = Some(time);
time::set_real_seconds(time.to_seconds(), true);
}
inner.read_reg(CMOS_REG_STATUS_C);
inner.counter += 1;
if inner.counter == REFRESH_INTERVAL {
inner.counter = 0;
}
true
}
}
impl Device for Rtc {
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let irq = Irq::External(ISA_IRQ_OFFSET + 8);
let intc = external_interrupt_controller()?;
self.inner.lock().setup_irq();
intc.register_irq(irq, Default::default(), self.clone())?;
intc.enable_irq(irq)?;
Ok(())
}
fn display_name(&self) -> &str {
"x86 RTC"
}
@@ -112,13 +163,15 @@ impl Rtc {
inner: IrqSafeSpinlock::new(Inner {
command: IoPort::new(0x70),
data: IoPort::new(0x71),
counter: 0,
last_timestamp: None,
}),
}
}
pub fn setup() -> Result<Arc<Self>, Error> {
let this = Arc::new(Self::new());
sysfs::nodes::add_rtc_node(this.clone());
unsafe { this.clone().init_irq() }?;
Ok(this)
}
}
+2 -4
View File
@@ -11,8 +11,6 @@ use libk::{
};
use static_assertions::{const_assert, const_assert_eq};
use crate::arch::x86_64::X86_64;
use super::exception;
pub mod ioapic;
@@ -117,8 +115,8 @@ unsafe extern "C" fn dummy_irq_handler() {
}
unsafe extern "C" fn ipi_handler() {
let ipi = Cpu::local().get_ipi();
X86_64::handle_ipi(ipi);
let cpu = Cpu::local();
todo!("Processor {} received an IPI", cpu.id());
}
global_asm!(
+3 -9
View File
@@ -4,12 +4,12 @@ use core::{arch::global_asm, mem::size_of};
use abi::{bitflags, primitive_enum, process::Signal};
use kernel_arch_x86::registers::{CR2, CR3};
use kernel_arch_x86_64::context::ExceptionFrame;
use libk::{arch::Cpu, task::thread::Thread};
use libk::task::thread::Thread;
use libk_mm::PageFaultKind;
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use tock_registers::interfaces::Readable;
use crate::arch::x86_64::{apic, X86_64};
use crate::arch::x86_64::apic;
primitive_enum! {
enum ExceptionKind: u64 {
@@ -231,13 +231,7 @@ extern "C" fn __x86_64_exception_handler(frame: *mut ExceptionFrame) {
}
extern "C" fn __x86_64_nmi_handler() -> ! {
let ipi = Cpu::local().get_ipi();
if let Some(ipi) = ipi {
X86_64::handle_ipi(Some(ipi));
unreachable!();
} else {
panic!("Spurious/unknown NMI received");
}
crate::panic::panic_secondary();
}
/// Initializes the interrupt descriptor table for the given CPU.
+5 -54
View File
@@ -1,20 +1,16 @@
//! x86-64 architecture implementation
use core::{ptr::null_mut, sync::atomic::Ordering};
use core::ptr::null_mut;
use abi::error::Error;
use acpi::{mcfg::Mcfg, AcpiTables, HpetInfo, InterruptModel};
use alloc::sync::Arc;
use device_api::{
device::Device,
interrupt::{IpiDeliveryTarget, IpiMessage},
};
use kernel_arch::{Architecture, ArchitectureImpl};
use device_api::device::Device;
use kernel_arch_x86::{
cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures, ExtEdxFeatures},
gdt,
};
use kernel_arch_x86_64::{mem, LocalApicInterface, PerCpuData, CPU_COUNT};
use kernel_arch_x86_64::{mem, LocalApicInterface, PerCpuData};
use libk::{
arch::Cpu,
config, debug,
@@ -31,10 +27,7 @@ use libk_mm::{
pointer::PhysicalRef,
table::EntryLevel,
};
use libk_util::{
sync::{IrqGuard, SpinFence},
OneTimeInit,
};
use libk_util::OneTimeInit;
use yboot_proto::{
v1::{self, AvailableMemoryRegion},
LoadProtocolV1,
@@ -52,7 +45,6 @@ use crate::{
Platform,
},
device::display::linear_fb::LinearFramebuffer,
panic,
util::call_init_array,
};
@@ -80,9 +72,7 @@ pub static PLATFORM: X86_64 = X86_64 {
fbconsole: OneTimeInit::new(),
};
static SHUTDOWN_FENCE: SpinFence = SpinFence::new();
//
impl Platform for X86_64 {
unsafe fn start_application_processors(&self) {
if let Some(acpi) = self.acpi.try_get() {
@@ -97,42 +87,9 @@ impl Platform for X86_64 {
smp::start_ap_cores(&pinfo);
}
}
unsafe fn power_off(&self) -> Result<!, Error> {
let _guard = IrqGuard::acquire();
let ap_count = CPU_COUNT.load(Ordering::Acquire) - 1;
if ap_count > 0 {
self.send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown)?;
SHUTDOWN_FENCE.wait_all(ap_count);
}
ygg_driver_acpi::power_off()
}
}
impl X86_64 {
fn handle_ipi(ipi: Option<IpiMessage>) {
let Some(ipi) = ipi else {
log::warn!("Spurious IPI received, assuming panic");
panic::panic_secondary();
};
match ipi {
IpiMessage::Shutdown => {
log::info!("Core halted");
SHUTDOWN_FENCE.signal();
ArchitectureImpl::halt()
}
IpiMessage::Panic => panic::panic_secondary(),
}
}
fn send_ipi(&self, target: IpiDeliveryTarget, message: IpiMessage) -> Result<(), Error> {
let cpu = Cpu::local();
cpu.local_apic.send_ipi(target, message)
}
fn set_boot_data(&self, data: BootData) {
match data {
BootData::YBoot(data) => {
@@ -239,12 +196,6 @@ impl X86_64 {
call_init_array();
x86::init_platform_devices(early);
extern "C" {
static __kernel_start: u8;
}
log::info!("Load base: {:p}", &raw const __kernel_start);
}
Ok(())
-7
View File
@@ -61,7 +61,6 @@ impl ResetDevice for Psci {
impl Psci {
const SYSTEM_RESET: u32 = 0x84000009;
const SYSTEM_OFF: u32 = 0x84000008;
#[inline]
unsafe fn call(&self, mut x0: u64, x1: u64, x2: u64, x3: u64) -> u64 {
@@ -75,12 +74,6 @@ impl Psci {
}
x0
}
/// Shut down the system
pub unsafe fn power_off(&self) -> Result<!, Error> {
self.call(Self::SYSTEM_OFF as _, 0, 0, 0);
unreachable!()
}
}
device_tree_driver! {
+6 -5
View File
@@ -3,12 +3,12 @@ use abi::{error::Error, io::TerminalOptions};
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@@ -79,7 +79,7 @@ struct Inner {
pub struct Ns16550a {
inner: OneTimeInit<Arc<Terminal<Inner>>>,
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
}
impl Io {
@@ -135,8 +135,9 @@ impl Device for Ns16550a {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
let io = self.inner.get().output().io.lock();
io.regs.IER.modify(IER::RDR::SET);
Ok(())
+6 -5
View File
@@ -4,12 +4,12 @@ use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, Hertz, ResetHandle},
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::{self, DebugSink},
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@@ -110,7 +110,7 @@ struct Inner {
/// Synopsys DesignWare 8250 UART
pub struct DwUart {
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
clk_baud: ClockHandle,
#[allow(unused)]
clk_apb: Option<ClockHandle>,
@@ -241,8 +241,9 @@ impl Device for DwUart {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, Default::default(), self.clone())?;
intc.enable_irq(self.irq.irq)?;
let output = self.inner.get().output();
let io = output.io.lock();
-2
View File
@@ -87,8 +87,6 @@ pub fn kinit() -> Result<(), Error> {
random::init();
loop {}
let root = setup_root().inspect_err(|error| {
log::error!("Cannot setup root filesystem: {error:?}");
})?;
-1
View File
@@ -77,7 +77,6 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "aarch64")] {
extern crate ygg_driver_bsp_arm;
extern crate ygg_driver_bsp_bcm283x;
extern crate ygg_driver_usb_dwc2;
} else if #[cfg(target_arch = "riscv64")] {
extern crate ygg_driver_bsp_riscv;
extern crate ygg_driver_bsp_jh7110;
+2 -15
View File
@@ -16,7 +16,7 @@ use abi::{
option::OptionValue,
path::Path,
process::{ExecveOptions, ProcessId},
system::{self, SystemControlVariant, SystemInfoVariant},
system::{self, SystemInfoVariant},
time::{ClockType, SystemTime},
};
use libk::{
@@ -26,10 +26,7 @@ use libk::{
};
use libk_mm::phys;
use crate::{
arch::{Platform, PLATFORM},
fs,
};
use crate::fs;
use super::run_with_io;
@@ -89,16 +86,6 @@ pub(crate) fn set_clock(ty: ClockType, value: &SystemTime) -> Result<(), Error>
}
}
pub(crate) fn system_control(option: u32, value: &mut [u8], size: usize) -> Result<usize, Error> {
let _ = (value, size);
let option = SystemControlVariant::try_from(option)?;
match option {
SystemControlVariant::PowerOff => {
unsafe { PLATFORM.power_off() }?;
}
}
}
pub(crate) fn get_system_info(option: u32, buffer: &mut [u8]) -> Result<usize, Error> {
let option = SystemInfoVariant::try_from(option)?;
match option {
-1
View File
@@ -80,7 +80,6 @@ syscall unmount(opts: &UnmountOptions) -> Result<()>;
syscall load_module(path: &str) -> Result<()>;
syscall filesystem_control(fd: Option<RawFd>, option: u32, value: &mut [u8], len: usize) -> Result<usize>;
syscall system_control(option: u32, value: &mut [u8], len: usize) -> Result<usize>;
syscall get_system_info(option: u32, value: &mut [u8]) -> Result<usize>;
-8
View File
@@ -21,14 +21,6 @@ option_group!(
}
);
request_group!(
#[doc = "Common system controls"]
pub enum SystemControlVariant<'de> {
#[doc = "Power down the system"]
0x1000: PowerOff((), ()),
}
);
abi_serde::impl_struct_serde!(
SystemMemoryStats: [total_usable_pages, allocated_pages, free_pages, page_size]
);
+1 -14
View File
@@ -1,10 +1,7 @@
//! System-related parameters
pub use abi::system::*;
use abi::{
error::Error,
option::{OptionValue, RequestValue},
};
use abi::{error::Error, option::OptionValue};
/// Helper macro for [get_system_info]
pub macro get_system_info($variant_ty:ty) {{
@@ -17,13 +14,3 @@ pub fn get_system_info<'de, T: OptionValue<'de>>(buffer: &'de mut [u8]) -> Resul
let len = unsafe { crate::sys::get_system_info(T::VARIANT.into(), buffer) }?;
T::load(&buffer[..len])
}
/// Performs an operation on the system, like power management, reset etc
pub fn system_control<'de, T: RequestValue<'de>>(
buffer: &'de mut [u8],
request: &T::Request,
) -> Result<T::Response, Error> {
let len = T::store_request(request, buffer)?;
let len = unsafe { crate::sys::system_control(T::VARIANT.into(), buffer, len) }?;
T::load_response(&buffer[..len])
}
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
set -e
build_dir=$3
cd "$build_dir/doomgeneric/doomgeneric"
make -f Makefile.yggdrasil SYSROOT=$Y_SYSROOT TARGET=$Y_TRIPLE
-17
View File
@@ -1,17 +0,0 @@
#!/bin/sh
set -e
REPO_URL="https://git.alnyan.me/yggdrasil/doomgeneric.git"
REPO_BRANCH="alnyan/yggdrasil"
build_dir=$3
mkdir -p "$build_dir"
if [ ! -f "$build_dir/.source-ready" ]; then
cd "$build_dir"
git clone --branch="$REPO_BRANCH" "$REPO_URL"
ln -s "$Y_WORKSPACE_ROOT" "$build_dir/doomgeneric/doomgeneric/doomgeneric-yggdrasil/yggdrasil-root"
touch "$build_dir/.source-ready"
fi
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
set -e
build_dir=$3
mkdir -p $Y_SYSROOT/bin
install -m0755 $build_dir/doomgeneric/doomgeneric/doomgeneric $Y_SYSROOT/bin/doomgeneric
-2
View File
@@ -1,2 +0,0 @@
description = "Doom port"
version = "1.0.0"
-1
View File
@@ -1 +0,0 @@
../meta-port-scripts/gnu-compile.sh
-1
View File
@@ -1 +0,0 @@
../meta-port-scripts/gnu-fetch.sh
-4
View File
@@ -1,4 +0,0 @@
#!/bin/sh
export GNU_PROJECT=gmp
export SRC_SHA256=e56fd59d76810932a0555aa15a14b61c16bed66110d3c75cc2ac49ddaa9ab24c
export GNU_CONFIGURE_OPTIONS=
-1
View File
@@ -1 +0,0 @@
../meta-port-scripts/gnu-install.sh
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
description = "GNU Multiple Precision Arithmetic Library"
version = "6.3.0"
+2
View File
@@ -2970,6 +2970,8 @@ name = "strace"
version = "0.1.0"
dependencies = [
"clap",
"cross",
"libc",
"runtime",
]
+3 -1
View File
@@ -26,7 +26,7 @@ members = [
"tools/shell",
"tools/strace",
]
exclude = ["dynload-program", "test-kernel-module", "lib/ygglibc", "target"]
exclude = ["dynload-program", "test-kernel-module", "lib/ygglibc"]
[workspace.dependencies]
log = "0.4.22"
@@ -65,6 +65,8 @@ sha2 = { version = "0.10.9" }
crypto-common = "0.1.6"
webpki-roots = "1.0.1"
raqote = { version = "0.8.3", default-features = false }
# Vendored/patched dependencies
rand = { git = "https://git.alnyan.me/yggdrasil/rand.git", branch = "alnyan/yggdrasil-rng_core-0.6.4" }
rand_core = { git = "https://git.alnyan.me/yggdrasil/rand.git", branch = "alnyan/yggdrasil-rng_core-0.6.4" }
-1
View File
@@ -1,5 +1,4 @@
#!/bin/sh
# Sync every 20 minutes
/bin/date set --from-rtc
/sbin/service start -- /bin/ntpc -i 1200 time.google.com:123
+1
View File
@@ -0,0 +1 @@
+1
View File
@@ -4,6 +4,7 @@
pub(crate) mod sys;
pub mod debug;
pub mod fs;
pub mod io;
pub mod mem;
+58
View File
@@ -1,6 +1,64 @@
use std::io;
#[derive(Debug)]
pub enum TraceEvent {
SyscallEntry(u64, [u64; 6]),
SyscallExit(i64),
Exited,
}
pub trait ChildTrace {
fn next_event(&mut self) -> io::Result<TraceEvent>;
fn resume(&mut self) -> io::Result<()>;
fn kill(&mut self) -> io::Result<()>;
unsafe fn peek_u8(&mut self, address: usize) -> io::Result<u8> {
let aligned = address & !7;
let shift = (address & 7) << 3;
let word = self.peek_u64(aligned)?;
Ok((word >> shift) as u8)
}
unsafe fn peek_u32(&mut self, address: usize) -> io::Result<u32> {
eprintln!("PEEK U32 @ {address:#x}");
assert_eq!(address & 3, 0);
let aligned = address & !7;
let shift = (address & 7) << 3;
let word = self.peek_u64(aligned)?;
Ok((word >> shift) as u32)
}
unsafe fn peek_u64(&mut self, address: usize) -> io::Result<u64>;
unsafe fn peek_bytes(&mut self, address: usize, buffer: &mut [u8]) -> io::Result<()> {
for i in 0..buffer.len() {
buffer[i] = self.peek_u8(address + i)?;
}
Ok(())
}
unsafe fn peek_cstr(&mut self, address: usize, buffer: &mut [u8]) -> io::Result<usize> {
let mut len = 0;
while len < buffer.len() - 1 {
let byte = self.peek_u8(address + len)?;
buffer[len] = byte;
if byte == 0 {
break;
}
len += 1;
}
Ok(len)
}
unsafe fn peek_usize(&mut self, address: usize) -> io::Result<usize> {
// FIXME I only support 64-bit archs
Ok(self.peek_u64(address)? as _)
}
}
pub trait CommandSpawnExt {
type ChildTrace: ChildTrace;
fn create_session(&mut self) -> io::Result<&mut Self>;
fn create_process_group(&mut self) -> io::Result<&mut Self>;
// TODO options for tracing across subchildren, etc
fn spawn_with_trace(&mut self) -> io::Result<Self::ChildTrace>;
}
+175 -2
View File
@@ -10,10 +10,12 @@ pub mod time;
pub mod timer;
use std::{
ffi::c_int,
ffi::{c_int, c_void},
io,
mem::MaybeUninit,
os::{fd::RawFd, unix::process::CommandExt},
process::Command,
ptr::null_mut,
sync::Mutex,
};
@@ -26,7 +28,126 @@ pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl};
pub use term::RawStdinImpl;
pub use timer::TimerFdImpl;
use crate::process::CommandSpawnExt;
use crate::process::{ChildTrace, CommandSpawnExt, TraceEvent};
pub struct ChildTraceImpl {
child: libc::pid_t,
}
impl ChildTrace for ChildTraceImpl {
fn next_event(&mut self) -> io::Result<TraceEvent> {
let ev = loop {
unsafe {
let mut status = 0;
if libc::waitpid(self.child, &mut status, 0) < 0 {
return Err(io::Error::last_os_error());
}
if libc::WIFSTOPPED(status) {
let stopsig = libc::WSTOPSIG(status);
if stopsig == libc::SIGTRAP | 0x80 {
let mut syscall_info = MaybeUninit::<libc::ptrace_syscall_info>::zeroed();
if libc::ptrace(
libc::PTRACE_GET_SYSCALL_INFO,
self.child,
size_of::<libc::ptrace_syscall_info>(),
syscall_info.as_mut_ptr(),
) < 0
{
return Err(io::Error::last_os_error());
}
let syscall_info = syscall_info.assume_init();
match syscall_info.op {
libc::PTRACE_SYSCALL_INFO_EXIT => {
break TraceEvent::SyscallExit(syscall_info.u.exit.sval);
}
libc::PTRACE_SYSCALL_INFO_ENTRY => {
break TraceEvent::SyscallEntry(
syscall_info.u.entry.nr,
syscall_info.u.entry.args,
);
}
_ => self.resume()?,
}
} else if stopsig == libc::SIGTRAP {
let event = (status >> 16) & 0xffff;
eprintln!("event = {event}");
match event {
libc::PTRACE_EVENT_EXIT => {
// Ignore
eprintln!("PTRACE_EVENT_EXIT");
self.resume()?;
}
libc::PTRACE_EVENT_VFORK => {
eprintln!("PTRACE_EVENT_VFORK");
self.resume()?;
}
libc::PTRACE_EVENT_EXEC => {
// Ignore
eprintln!("PTRACE_EVENT_EXEC");
self.resume()?;
}
_ => todo!(),
}
} else {
todo!("signum == {stopsig}");
}
} else if libc::WIFEXITED(status) {
break TraceEvent::Exited;
} else {
todo!();
}
}
};
Ok(ev)
}
fn kill(&mut self) -> io::Result<()> {
todo!()
}
fn resume(&mut self) -> io::Result<()> {
if unsafe {
libc::ptrace(
libc::PTRACE_SYSCALL,
self.child,
null_mut::<c_void>(),
null_mut::<c_void>(),
)
} == 0
{
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
unsafe fn peek_u64(&mut self, address: usize) -> io::Result<u64> {
libc::__errno_location().write_volatile(0);
let word = libc::ptrace(
libc::PTRACE_PEEKDATA,
self.child,
address,
null_mut::<c_void>(),
);
if libc::__errno_location().read_volatile() != 0 {
Err(io::Error::last_os_error())
} else {
Ok(word as _)
}
}
}
impl Drop for ChildTraceImpl {
fn drop(&mut self) {
let mut ignore = 0;
unsafe {
libc::ptrace(libc::PTRACE_DETACH, self.child);
libc::waitpid(self.child, &mut ignore, 0);
}
}
}
fn dummy_sigint() {}
@@ -61,6 +182,8 @@ pub fn clone_fd(fd: RawFd) -> io::Result<RawFd> {
}
impl CommandSpawnExt for Command {
type ChildTrace = ChildTraceImpl;
fn create_process_group(&mut self) -> io::Result<&mut Self> {
Ok(self.process_group(0))
}
@@ -69,4 +192,54 @@ impl CommandSpawnExt for Command {
// TODO
Ok(self)
}
fn spawn_with_trace(&mut self) -> io::Result<Self::ChildTrace> {
unsafe {
match libc::fork() {
0 => {
// Child
// if libc::ptrace(libc::PTRACE_TRACEME, libc::getpid()) != 0 {
// panic!("PTRACE_TRACEME: {}", io::Error::last_os_error());
// }
libc::raise(libc::SIGSTOP);
panic!("exec error: {}", self.exec());
}
code if code < 0 => {
// Error
Err(io::Error::last_os_error())
}
pid => {
let options = libc::PTRACE_O_TRACESYSGOOD | libc::PTRACE_O_TRACEEXEC;
let mut ignore = 0;
// Parent
if libc::ptrace(
libc::PTRACE_SEIZE,
pid,
null_mut::<c_void>(),
null_mut::<c_void>(),
) != 0
{
// TODO waitpid child? kill child?
eprintln!("PTRACE_SEIZE error");
return Err(io::Error::last_os_error());
}
if libc::waitpid(pid, &mut ignore, 0) < 0 {
return Err(io::Error::last_os_error());
}
if libc::ptrace(libc::PTRACE_SETOPTIONS, pid, null_mut::<c_void>(), options)
!= 0
{
return Err(io::Error::last_os_error());
}
libc::ptrace(
libc::PTRACE_CONT,
pid,
null_mut::<c_void>(),
null_mut::<c_void>(),
);
Ok(ChildTraceImpl { child: pid })
}
}
}
}
}
+146 -3
View File
@@ -11,8 +11,20 @@ pub mod timer;
use std::{
io,
os::{fd::RawFd, yggdrasil::process::CommandExt},
process::Command,
mem::MaybeUninit,
os::{
fd::RawFd,
yggdrasil::process::{ChildExt, CommandExt},
},
process::{Child, Command},
};
use runtime::{
abi::{
arch::SavedFrame,
debug::{self, TraceFlags},
},
rt::{debug::debug_control, process::ThreadEvent},
};
pub use mem::{FileMappingImpl, SharedMemoryImpl};
@@ -24,7 +36,131 @@ pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl};
pub use term::RawStdinImpl;
pub use timer::TimerFdImpl;
use crate::process::CommandSpawnExt;
use crate::process::{ChildTrace, CommandSpawnExt, TraceEvent};
pub struct ChildTraceImpl {
#[allow(unused)]
child: Child,
buffer: [u8; 512],
tid: u32,
}
impl ChildTraceImpl {
fn attach(child: Child) -> io::Result<Self> {
let mut buffer = [0; 512];
let tid = child.main_thread_id()?;
debug_control::<debug::SetTraceFlags>(
tid,
&mut buffer,
&(TraceFlags::SYSCALL_ENTRY | TraceFlags::SYSCALL_EXIT),
)
.map_err(io::Error::from)
.unwrap();
Ok(Self { child, tid, buffer })
}
fn read_regs(&mut self) -> io::Result<SavedFrame> {
debug_control::<debug::GetRegisters>(self.tid, &mut self.buffer, &())
.map_err(io::Error::from)
}
}
#[cfg(any(rust_analyzer, target_arch = "aarch64"))]
impl ChildTraceImpl {
fn read_syscall_entry(&mut self) -> io::Result<(u64, [u64; 6])> {
let frame = self.read_regs()?;
Ok((
frame.gp_regs[8] as _,
[
frame.gp_regs[0] as _,
frame.gp_regs[1] as _,
frame.gp_regs[2] as _,
frame.gp_regs[3] as _,
frame.gp_regs[4] as _,
frame.gp_regs[5] as _,
],
))
}
fn read_syscall_exit(&mut self) -> io::Result<u64> {
let frame = self.read_regs()?;
Ok(frame.gp_regs[0] as _)
}
}
#[cfg(any(rust_analyzer, target_arch = "x86_64"))]
impl ChildTraceImpl {
fn read_syscall_entry(&mut self) -> io::Result<(u64, [u64; 6])> {
let frame = self.read_regs()?;
Ok((
frame.rax as _,
[
frame.rdi as _,
frame.rsi as _,
frame.rdx as _,
frame.r10 as _,
frame.r8 as _,
frame.r9 as _,
],
))
}
fn read_syscall_exit(&mut self) -> io::Result<u64> {
let frame = self.read_regs()?;
Ok(frame.rax as _)
}
}
impl ChildTrace for ChildTraceImpl {
unsafe fn peek_u64(&mut self, address: usize) -> io::Result<u64> {
let word = debug_control::<debug::ReadMemory>(self.tid, &mut self.buffer, &address)?;
Ok(word as _)
}
fn kill(&mut self) -> io::Result<()> {
todo!()
}
fn resume(&mut self) -> io::Result<()> {
debug_control::<debug::Resume>(self.tid, &mut self.buffer, &false).map_err(io::Error::from)
}
fn next_event(&mut self) -> io::Result<TraceEvent> {
loop {
let mut event = MaybeUninit::uninit();
unsafe { runtime::rt::sys::wait_thread(self.tid, &mut event) }
.map_err(io::Error::from)?;
let event = unsafe { event.assume_init() };
match event {
ThreadEvent::Trace(trace) => {
let event = match trace.payload {
debug::TraceEventPayload::SyscallEntry(_seq) => {
let (nr, args) = self.read_syscall_entry()?;
TraceEvent::SyscallEntry(nr, args)
}
debug::TraceEventPayload::SyscallExit(_seq) => {
let status = self.read_syscall_exit()?;
TraceEvent::SyscallExit(status as _)
}
debug::TraceEventPayload::SingleStep => {
self.resume()?;
continue;
}
};
break Ok(event);
}
ThreadEvent::Exited => {
// TODO status
break Ok(TraceEvent::Exited);
}
}
}
}
}
pub fn set_sigint_handler(_handler: fn()) {}
@@ -45,6 +181,13 @@ pub fn clone_fd(fd: RawFd) -> io::Result<RawFd> {
}
impl CommandSpawnExt for Command {
type ChildTrace = ChildTraceImpl;
fn spawn_with_trace(&mut self) -> io::Result<Self::ChildTrace> {
unsafe { self.attach_tracing() };
self.spawn().and_then(ChildTraceImpl::attach)
}
fn create_process_group(&mut self) -> io::Result<&mut Self> {
let group = unsafe { runtime::rt::sys::create_process_group() };
Ok(self.process_group(group))
@@ -56,7 +56,6 @@ unsafe extern "C" fn posix_spawn(
arguments: &args,
environment: &envs,
directory: None,
root: None,
optional: &[
SpawnOption::CopyFile {
source: RawFd::STDIN,
-15
View File
@@ -33,9 +33,6 @@ yggdrasil-abi.workspace = true
yggdrasil-rt.workspace = true
runtime.workspace = true
[dev-dependencies]
runtime.workspace = true
[lib]
path = "src/lib.rs"
@@ -44,14 +41,6 @@ path = "src/lib.rs"
name = "mount"
path = "src/mount.rs"
[[bin]]
name = "poweroff"
path = "src/poweroff.rs"
[[bin]]
name = "reboot"
path = "src/reboot.rs"
[[bin]]
name = "chroot"
path = "src/chroot.rs"
@@ -81,10 +70,6 @@ path = "src/echo.rs"
name = "ls"
path = "src/ls.rs"
[[bin]]
name = "tree"
path = "src/tree.rs"
[[bin]]
name = "mv"
path = "src/mv.rs"
+7 -68
View File
@@ -1,86 +1,25 @@
#![feature(rustc_private)]
use std::{fs, io, process::ExitCode};
use std::process::ExitCode;
use chrono::DateTime;
use clap::{Parser, Subcommand};
use cross::time::set_real_time;
use runtime::rt::time::{get_real_time, SystemTime};
const DEFAULT_RTC_PATH: &str = "/sys/device/rtc/rtc0/time";
#[derive(Debug, Parser)]
struct Args {
#[clap(subcommand)]
action: Option<Action>,
}
#[derive(Debug, Subcommand)]
enum Action {
Get {
#[clap(short, long)]
rtc: bool,
},
Set {
#[clap(short = 'r', long)]
from_rtc: bool,
},
}
impl Default for Action {
fn default() -> Self {
Self::Get { rtc: false }
}
}
use yggdrasil_rt::time::get_real_time;
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("Could not get current time: {0:?}")]
Io(#[from] io::Error),
GetTime(yggdrasil_rt::Error),
#[error("Time conversion error")]
UtcTime,
}
fn read_rtc_time() -> Result<SystemTime, Error> {
let rtc_timestamp: u64 = fs::read_to_string(DEFAULT_RTC_PATH)?
.trim()
.parse()
.map_err(|_| Error::UtcTime)?;
Ok(SystemTime::new(rtc_timestamp, 0))
}
fn get_date(rtc: bool) -> Result<(), Error> {
let time = if rtc {
read_rtc_time()?
} else {
get_real_time().map_err(io::Error::from)?
};
let now = DateTime::from_timestamp(time.seconds() as _, time.subsec_nanos() as _)
.ok_or(Error::UtcTime)?;
fn run() -> Result<(), Error> {
let now = get_real_time().map_err(Error::GetTime)?;
let now = DateTime::from_timestamp(now.seconds() as _, now.subsec_nanos() as _).ok_or(Error::UtcTime)?;
println!("{now}");
Ok(())
}
fn set_date(from_rtc: bool) -> Result<(), Error> {
let time = if from_rtc { read_rtc_time()? } else { todo!() };
set_real_time(time.seconds(), 0)?;
Ok(())
}
fn run(args: Args) -> Result<(), Error> {
let action = args.action.unwrap_or_default();
match action {
Action::Get { rtc } => get_date(rtc),
Action::Set { from_rtc } => set_date(from_rtc),
}
}
fn main() -> ExitCode {
let args = Args::parse();
match run(args) {
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("Error: {error}");
-15
View File
@@ -1,15 +0,0 @@
#![feature(rustc_private)]
use std::{io, process::ExitCode};
use runtime::{abi::system, rt::system::system_control};
fn main() -> ExitCode {
if let Err(error) = system_control::<system::PowerOff>(&mut [], &()) {
let error = io::Error::from(error);
eprintln!("{error}");
ExitCode::FAILURE
} else {
ExitCode::SUCCESS
}
}
-1
View File
@@ -1 +0,0 @@
fn main() {}
-90
View File
@@ -1,90 +0,0 @@
use std::{
fs, io,
path::{Path, PathBuf},
process::ExitCode,
};
use clap::Parser;
fn list<P: AsRef<Path>>(path: P, depth: usize, last_mask: u64) -> io::Result<()> {
fn indent(depth: usize, mask: u64) {
for i in 0..depth + 1 {
if i < depth {
if (1 << i) & mask == 0 {
print!("");
} else {
print!(" ");
}
} else if (1 << i) & mask == 0 {
print!("├─");
} else {
print!("└─");
}
}
}
let mut entries = vec![];
let dir = fs::read_dir(path)?;
for entry in dir {
let Ok((ty, entry)) = entry.and_then(|e| Ok((e.file_type()?, e))) else {
entries.push(None);
continue;
};
let name = entry.file_name().into_string().unwrap();
if name == "." || name == ".." {
continue;
}
entries.push(Some((name, entry.path(), ty.is_dir())));
}
entries.sort_by(|a, b| {
let (Some((a, _, _)), Some((b, _, _))) = (a.as_ref(), b.as_ref()) else {
return Ord::cmp(&a.is_none(), &b.is_none());
};
Ord::cmp(a, b)
});
let len = entries.len();
for (i, entry) in entries.into_iter().enumerate() {
let last_bit = ((i == len - 1) as u64) << depth;
indent(depth, last_mask | last_bit);
let Some((name, path, dir)) = entry else {
println!("<error>");
continue;
};
println!("{name}");
if dir {
list(path, depth + 1, last_mask | last_bit).ok();
}
}
Ok(())
}
#[derive(Debug, Parser)]
struct Args {
path: Option<PathBuf>,
}
fn run<P: AsRef<Path>>(path: P) -> io::Result<()> {
list(path, 0, 0)
}
fn main() -> ExitCode {
let args = Args::parse();
let path = args.path.unwrap_or_else(|| PathBuf::from("."));
match run(&path) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("{}: {}", path.display(), error);
ExitCode::FAILURE
}
}
}
-65
View File
@@ -1,68 +1,3 @@
#![feature(yggdrasil_os, if_let_guard)]
fn main() {}
// use std::{fmt::{LowerHex, Display}, io, path::PathBuf, process::Command};
//
// use clap::Parser;
// use debugger::{Debugger, SymbolResolver};
// use imp::TargetImpl;
// use yggdrasil_abi::arch::SavedFrame;
//
// #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
// #[path = "x86.rs"]
// pub mod imp;
// #[cfg(any(target_arch = "aarch64", rust_analyzer))]
// #[path = "aarch64.rs"]
// pub mod imp;
//
// pub mod comm;
// pub mod state;
//
// pub mod debugger;
//
// #[derive(thiserror::Error, Debug)]
// pub enum Error {
// #[error("I/O error: {0}")]
// IoError(#[from] io::Error),
// #[error("Terminal error: {0}")]
// TermError(#[from] libterm::Error),
// #[error("Debug control error: {0:?}")]
// DebugError(yggdrasil_rt::Error),
// #[error("Invalid address: {0:?}")]
// InvalidAddress(String)
// }
//
// pub trait Target {
// type Instruction;
// type InstructionFormatter: InstructionFormatter<Self::Instruction>;
// type Register: LowerHex;
//
// fn disassemble(
// window: &[u8],
// ip: usize,
// limit: usize,
// ) -> Result<Vec<(usize, Self::Instruction)>, Error>;
// fn new_instruction_formatter(resolver: SymbolResolver) -> Self::InstructionFormatter;
//
// fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>);
// fn flags_register_as_display(frame: &SavedFrame) -> impl Display;
// fn real_ip(frame: &SavedFrame) -> usize;
// }
//
// pub trait InstructionFormatter<I> {
// fn format_instruction(&mut self, insn: &I, out: &mut String);
// }
//
// #[derive(Parser)]
// struct Args {
// program: PathBuf,
// }
//
// fn main() {
// let args = Args::parse();
//
// let command = Command::new(&args.program);
// let debug: Debugger<TargetImpl> = Debugger::from_command(&args.program, command).unwrap();
//
// debug.run().unwrap();
// }
+11 -1
View File
@@ -4,9 +4,19 @@ version = "0.1.0"
edition = "2021"
[dependencies]
runtime.workspace = true
cross.workspace = true
clap.workspace = true
[target.'cfg(target_os = "yggdrasil")'.dependencies]
runtime.workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
libc = "*"
[dev-dependencies]
runtime.workspace = true
libc = "*"
[lints]
workspace = true
@@ -0,0 +1,175 @@
#[cfg(any(rust_analyzer, target_arch = "x86_64"))]
#[path = "x86_64.rs"]
pub mod imp;
use std::fmt;
pub use imp::*;
use libc::{c_int, c_uint};
macro_rules! impl_ioctls {
($f:expr, $v:expr, $ty:ty, [$($ioctl:ident),* $(,)?]) => {{
#[allow(unreachable_patterns)]
let v = match $v as $ty {
$(libc::$ioctl => stringify!($ioctl),)*
_ => return write!($f, "{:#x}", $v),
};
write!($f, "{v}")
}};
}
fn print_ioctl<W: fmt::Write>(f: &mut W, v: c_uint) -> fmt::Result {
impl_ioctls!(
f,
v,
u64,
[
TCGETS,
TCSETS,
TCSETSW,
TCSETSF,
TCGETA,
TCSETA,
TCSETAW,
TCSETAF,
TCSBRK,
TCXONC,
TCFLSH,
TIOCEXCL,
TIOCNXCL,
TIOCSCTTY,
TIOCGPGRP,
TIOCSPGRP,
TIOCOUTQ,
TIOCSTI,
TIOCGWINSZ,
TIOCSWINSZ,
TIOCMGET,
TIOCMBIS,
TIOCMBIC,
TIOCMSET,
TIOCGSOFTCAR,
TIOCSSOFTCAR,
FIONREAD,
TIOCLINUX,
TIOCCONS,
TIOCGSERIAL,
TIOCSSERIAL,
TIOCPKT,
FIONBIO,
TIOCNOTTY,
TIOCSETD,
TIOCGETD,
TCSBRKP,
TIOCSBRK,
TIOCCBRK,
TIOCGSID,
TCGETS2,
TCSETS2,
TCSETSW2,
TCSETSF2,
TIOCGRS485,
TIOCSRS485,
TIOCGPTN,
TIOCSPTLCK,
TIOCGDEV,
TCGETX,
TCSETX,
TCSETXF,
TCSETXW,
TIOCSIG,
TIOCVHANGUP,
TIOCGPKT,
TIOCGPTLCK,
TIOCGEXCL,
TIOCGPTPEER,
FIONCLEX,
FIOCLEX,
FIOASYNC,
TIOCSERCONFIG,
TIOCSERGWILD,
TIOCSERSWILD,
TIOCGLCKTRMIOS,
TIOCSLCKTRMIOS,
TIOCSERGSTRUCT,
TIOCSERGETLSR,
TIOCSERGETMULTI,
TIOCSERSETMULTI,
TIOCMIWAIT,
TIOCGICOUNT,
]
)
}
fn print_prctl<W: fmt::Write>(f: &mut W, c: c_int) -> fmt::Result {
impl_ioctls!(
f,
c,
c_int,
[
PR_SET_PDEATHSIG,
PR_GET_PDEATHSIG,
PR_GET_DUMPABLE,
PR_SET_DUMPABLE,
PR_GET_UNALIGN,
PR_SET_UNALIGN,
PR_GET_KEEPCAPS,
PR_SET_KEEPCAPS,
PR_GET_FPEMU,
PR_SET_FPEMU,
PR_GET_FPEXC,
PR_SET_FPEXC,
PR_GET_TIMING,
PR_SET_TIMING,
PR_SET_NAME,
PR_GET_NAME,
PR_GET_ENDIAN,
PR_SET_ENDIAN,
PR_GET_SECCOMP,
PR_SET_SECCOMP,
PR_CAPBSET_READ,
PR_CAPBSET_DROP,
PR_GET_TSC,
PR_SET_TSC,
PR_GET_SECUREBITS,
PR_SET_SECUREBITS,
PR_SET_TIMERSLACK,
PR_GET_TIMERSLACK,
PR_TASK_PERF_EVENTS_DISABLE,
PR_TASK_PERF_EVENTS_ENABLE,
PR_MCE_KILL,
PR_SET_MM,
PR_SET_PTRACER,
PR_SET_CHILD_SUBREAPER,
PR_GET_CHILD_SUBREAPER,
PR_SET_NO_NEW_PRIVS,
PR_GET_NO_NEW_PRIVS,
PR_GET_TID_ADDRESS,
PR_SET_THP_DISABLE,
PR_GET_THP_DISABLE,
PR_MPX_ENABLE_MANAGEMENT,
PR_MPX_DISABLE_MANAGEMENT,
PR_SET_FP_MODE,
PR_GET_FP_MODE,
PR_CAP_AMBIENT,
PR_GET_SPECULATION_CTRL,
PR_SET_SPECULATION_CTRL,
PR_SCHED_CORE,
PR_SET_MDWE,
PR_GET_MDWE,
PR_SET_VMA,
]
)
}
fn print_access_mode<W: fmt::Write>(f: &mut W, mode: c_int) -> fmt::Result {
let s = match mode {
libc::F_OK => "F_OK",
libc::W_OK => "W_OK",
libc::R_OK => "R_OK",
libc::X_OK => "X_OK",
_ => return write!(f, "{mode:#x}"),
};
write!(f, "{s}")
}
@@ -0,0 +1,123 @@
use std::{ffi::c_void, fmt};
use cross::process::ChildTrace;
use libc::{c_char, c_int, c_long, c_uint, c_ulong};
use crate::definition::{
imp::{print_access_mode, print_ioctl, print_prctl},
print_cstring, PrintSyscallArgument, Syscall,
};
pub enum SyscallArgument {
Fd(c_int),
MaybeFd(c_int),
Bytes(*const c_char),
BytesMut(*const c_char),
Size(usize),
Filename(*const c_char),
OpenOptions(c_int),
FileMode(c_int),
Ptr(*const c_void),
Long(c_long),
ULong(c_ulong),
Int(c_int),
UInt(c_uint),
Whence(c_int),
Off(libc::off_t),
LOff(libc::loff_t),
IoctlCmd(c_uint),
PrctlCmd(c_int),
AccessMode(c_int),
AtFd(c_int),
}
impl PrintSyscallArgument for SyscallArgument {
fn print_syscall_argument<W: fmt::Write, T: ChildTrace>(&self, f: &mut W, trace: &mut T) {
match self {
Self::Fd(libc::STDIN_FILENO) => write!(f, "STDIN_FILENO"),
Self::Fd(libc::STDOUT_FILENO) => write!(f, "STDOUT_FILENO"),
Self::Fd(libc::STDERR_FILENO) => write!(f, "STDERR_FILENO"),
Self::Fd(fd) => write!(f, "{fd}"),
Self::MaybeFd(-1) => write!(f, "<none>"),
Self::MaybeFd(fd) => write!(f, "{fd}"),
Self::Bytes(bytes) => write!(f, "{bytes:p}"),
Self::BytesMut(bytes) => write!(f, "{bytes:p}"),
Self::Size(size) if *size <= 999 => write!(f, "{size}"),
Self::Size(size) => write!(f, "{size:#x}"),
Self::Filename(filename) => print_cstring(f, trace, filename.addr()),
Self::OpenOptions(opts) => write!(f, "{opts:#x}"),
Self::FileMode(mode) => write!(f, "0{mode:o}"),
Self::Ptr(ptr) => write!(f, "{ptr:p}"),
Self::Long(val) => write!(f, "{val}"),
Self::ULong(val) => write!(f, "{val}"),
Self::Int(val) => write!(f, "{val}"),
Self::UInt(val) => write!(f, "{val}"),
Self::Whence(libc::SEEK_SET) => write!(f, "SEEK_SET"),
Self::Whence(libc::SEEK_CUR) => write!(f, "SEEK_CUR"),
Self::Whence(libc::SEEK_END) => write!(f, "SEEK_END"),
Self::Whence(w) => write!(f, "{w}"),
Self::Off(off) => write!(f, "{off}"),
Self::LOff(off) => write!(f, "{off}"),
&Self::IoctlCmd(v) => print_ioctl(f, v),
&Self::PrctlCmd(v) => print_prctl(f, v),
&Self::AccessMode(m) => print_access_mode(f, m),
Self::AtFd(libc::AT_FDCWD) => write!(f, "AT_FDCWD"),
Self::AtFd(fd) => write!(f, "{fd}"),
}
.ok();
}
}
macro_rules! impl_syscall_args {
($input:expr, [$($collect:expr),*], $i:expr, [$arg:ident, $($tail:ident),+]) => {
impl_syscall_args!($input, [$($collect,)* (SyscallArgument::$arg($input[$i] as _))], $i + 1, [$($tail),+])
};
($input:expr, [$($collect:expr),*], $i:expr, [$arg:ident]) => {
vec![$($collect,)* (SyscallArgument::$arg($input[$i] as _))]
};
($input:expr, [], $i:expr, []) => {
vec![]
};
}
macro_rules! impl_syscall_parse {
($(
$nr:literal => $name:ident ( $($arg:ident),* )
),+ $(,)?) => {
pub fn parse_syscall(nr: u64, args: &[u64]) -> Option<Syscall> {
Some(match nr {
$($nr => Syscall(
stringify!($name),
impl_syscall_args!(args, [], 0, [$($arg),*])
),)+
_ => return None,
})
}
};
}
impl_syscall_parse!(
0 => read(Fd, BytesMut, Size),
1 => write(Fd, Bytes, Size),
2 => open(Filename, OpenOptions, FileMode),
3 => close(Fd),
4 => stat(Filename, BytesMut),
5 => fstat(Fd, BytesMut),
6 => lstat(Filename, BytesMut),
7 => poll(Ptr, ULong, Long),
8 => lseek(Fd, Off, Whence),
9 => mmap(Ptr, ULong, ULong, ULong, MaybeFd, ULong),
10 => mprotect(Ptr, Size, ULong),
11 => munmap(Ptr, Size),
12 => brk(Ptr),
// TODO rt_...
16 => ioctl(Fd, IoctlCmd, ULong),
17 => pread64(Fd, BytesMut, Size, LOff),
21 => access(Filename, AccessMode),
157 => prctl(PrctlCmd, ULong, ULong, ULong),
218 => set_tid_address(Ptr),
334 => rseq(Ptr, UInt, Int, UInt),
257 => openat(AtFd, Filename, OpenOptions, FileMode),
262 => newfstatat(AtFd, Filename, Ptr, Int),
24 => sched_yield(),
);
@@ -0,0 +1,67 @@
use std::fmt;
use cross::process::ChildTrace;
#[cfg(any(rust_analyzer, target_os = "linux"))]
#[path = "linux/mod.rs"]
pub mod imp;
#[cfg(any(rust_analyzer, target_os = "yggdrasil"))]
#[path = "yggdrasil.rs"]
pub mod imp;
pub use imp::*;
pub trait PrintSyscallArgument {
fn print_syscall_argument<W: fmt::Write, T: ChildTrace>(&self, f: &mut W, trace: &mut T);
}
pub struct Syscall(pub &'static str, pub Vec<SyscallArgument>);
impl Syscall {
pub fn print<W: fmt::Write, T: ChildTrace>(&self, f: &mut W, trace: &mut T) {
write!(f, "{}(", self.0).ok();
for (i, arg) in self.1.iter().enumerate() {
if i != 0 {
write!(f, ", ").ok();
}
arg.print_syscall_argument(f, trace);
}
write!(f, ")").ok();
}
}
pub fn print_string<W: fmt::Write, T: ChildTrace>(
f: &mut W,
trace: &mut T,
address: usize,
len: usize,
) -> fmt::Result {
let mut buffer = [0; 64];
let len = len.min(buffer.len());
if let Ok(()) = unsafe { trace.peek_bytes(address, &mut buffer[..len]) } {
if let Ok(s) = std::str::from_utf8(&buffer[..len]) {
write!(f, "{s:?}")
} else {
todo!()
}
} else {
write!(f, "<error str {address:#x}>")
}
}
pub fn print_cstring<W: fmt::Write, T: ChildTrace>(
f: &mut W,
trace: &mut T,
address: usize,
) -> fmt::Result {
let mut buffer = [0; 64];
if let Ok(len) = unsafe { trace.peek_cstr(address, &mut buffer) } {
if let Ok(s) = std::str::from_utf8(&buffer[..len]) {
write!(f, "{s:?}")
} else {
todo!()
}
} else {
write!(f, "<error str {address:#x}>")
}
}
@@ -0,0 +1,335 @@
use std::fmt;
use cross::process::ChildTrace;
use runtime::{abi::SyscallFunction, abi_lib::SyscallRegister, rt::io::RawFd};
use crate::definition::{print_string, PrintSyscallArgument, Syscall};
pub enum SyscallArgument {
Bytes(u64, u64),
BytesMut(u64, u64),
MaybePtr(u64),
Fd(u64),
OptionFd(u64),
Ptr(u64),
Size(u64),
U64(u64),
I64(i64),
U32(u32),
I32(i32),
PtrSystemTime(u64),
ClockType(u64),
Filename(u64, u64),
}
pub enum ArgType {
Bytes,
BytesMut,
MaybePtr,
Fd,
OptionFd,
Ptr,
Size,
U64,
I64,
U32,
I32,
PtrSystemTime,
ClockType,
Filename,
}
struct SyscallDefinition(SyscallFunction, &'static str, &'static [ArgType]);
impl PrintSyscallArgument for SyscallArgument {
fn print_syscall_argument<W: fmt::Write, T: ChildTrace>(&self, f: &mut W, trace: &mut T) {
match self {
&Self::MaybePtr(0) => write!(f, "None"),
Self::Fd(fd) => {
let fd = unsafe { RawFd::from_raw(*fd as _) };
match fd {
RawFd::STDIN => write!(f, "STDIN"),
RawFd::STDOUT => write!(f, "STDOUT"),
RawFd::STDERR => write!(f, "STDERR"),
_ => write!(f, "{fd:?}"),
}
}
Self::OptionFd(fd) => match Option::<RawFd>::from_syscall_register(*fd as _) {
Some(fd) => write!(f, "Some({fd:?})"),
None => write!(f, "None"),
},
Self::MaybePtr(addr) => write!(f, "Some({addr:#x})"),
Self::Ptr(ptr) => write!(f, "{ptr:#x}"),
Self::U64(val) => write!(f, "{val}"),
Self::I64(val) => write!(f, "{val}"),
Self::U32(val) => write!(f, "{val}"),
Self::I32(val) => write!(f, "{val}"),
Self::Size(val) => write!(f, "{val}"),
Self::Bytes(addr, len) => write!(f, "&[{addr:#x}; {len}]"),
Self::BytesMut(addr, len) => write!(f, "&mut [{addr:#x}; {len}]"),
Self::PtrSystemTime(ptr) => write!(f, "{ptr:#x}"),
Self::ClockType(1) => write!(f, "RealTime"),
Self::ClockType(2) => write!(f, "Monotonic"),
Self::ClockType(v) => write!(f, "{v}"),
Self::Filename(ptr, len) => print_string(f, trace, *ptr as _, *len as _),
}
.ok();
}
}
const DEFS: &[SyscallDefinition] = &const {
use ArgType::*;
[
SyscallDefinition(SyscallFunction::GetRandom, "get_random", &[BytesMut]),
SyscallDefinition(
SyscallFunction::GetClock,
"get_clock",
&[ClockType, PtrSystemTime],
),
SyscallDefinition(
SyscallFunction::SetClock,
"set_clock",
&[ClockType, PtrSystemTime],
),
SyscallDefinition(SyscallFunction::Mount, "mount", &[Ptr]), // TODO
SyscallDefinition(SyscallFunction::Unmount, "unmount", &[Ptr]), // TODO
SyscallDefinition(SyscallFunction::LoadModule, "load_module", &[Filename]),
SyscallDefinition(
SyscallFunction::FilesystemControl,
"filesystem_control",
&[OptionFd, U32, Size],
),
SyscallDefinition(
SyscallFunction::GetSystemInfo,
"get_system_info",
&[U32, BytesMut],
), // TODO
// Memory management
SyscallDefinition(
SyscallFunction::MapMemory,
"map_memory",
&[MaybePtr, Size, U32, Ptr],
),
SyscallDefinition(SyscallFunction::UnmapMemory, "unmap_memory", &[Ptr, Size]),
// Process/thread management
SyscallDefinition(
SyscallFunction::CreateProcessGroup,
"create_process_group",
&[],
),
SyscallDefinition(
SyscallFunction::GetProcessGroupId,
"get_process_group_id",
&[],
),
SyscallDefinition(SyscallFunction::ExitProcess, "exit_process", &[U64]), // TODO
SyscallDefinition(SyscallFunction::SpawnProcess, "spawn_process", &[Ptr]), // TODO
SyscallDefinition(
SyscallFunction::WaitProcess,
"wait_process",
&[Ptr, Ptr, U32],
), // TODO
SyscallDefinition(SyscallFunction::GetPid, "get_pid", &[]),
SyscallDefinition(SyscallFunction::GetTid, "get_tid", &[]),
SyscallDefinition(SyscallFunction::SpawnThread, "spawn_thread", &[Ptr]), // TODO
SyscallDefinition(SyscallFunction::ExitThread, "exit_thread", &[]),
SyscallDefinition(SyscallFunction::WaitThread, "wait_thread", &[U32, Ptr]), // TODO
SyscallDefinition(
SyscallFunction::GetThreadOption,
"get_thread_option",
&[U32, BytesMut],
), // TODO
SyscallDefinition(
SyscallFunction::SetThreadOption,
"set_thread_option",
&[U32, Bytes],
), // TODO
SyscallDefinition(
SyscallFunction::GetProcessOption,
"get_process_option",
&[U32, U32, BytesMut],
), // TODO
SyscallDefinition(
SyscallFunction::SetProcessOption,
"set_process_option",
&[U32, U32, Bytes],
), // TODO
SyscallDefinition(SyscallFunction::Nanosleep, "nanosleep", &[Ptr, Ptr]), // TODO
SyscallDefinition(SyscallFunction::ExitSignal, "exit_signal", &[Ptr]), // TODO
SyscallDefinition(SyscallFunction::SendSignal, "send_signal", &[U32, U32]), // TODO
SyscallDefinition(SyscallFunction::Mutex, "mutex", &[Ptr, Ptr]), // TODO
SyscallDefinition(SyscallFunction::StartSession, "start_session", &[]),
// I/O
SyscallDefinition(
SyscallFunction::Open,
"open",
&[OptionFd, Filename, U32, U32],
), // TODO
SyscallDefinition(
SyscallFunction::CheckAccess,
"check_access",
&[OptionFd, Filename, U32],
), // TODO
SyscallDefinition(SyscallFunction::Close, "close", &[Fd]),
SyscallDefinition(SyscallFunction::Write, "write", &[Fd, Bytes]),
SyscallDefinition(SyscallFunction::Read, "read", &[Fd, BytesMut]),
SyscallDefinition(SyscallFunction::Seek, "seek", &[Fd, U32, Ptr]), // TODO
SyscallDefinition(SyscallFunction::Truncate, "truncate", &[Fd, U64]), // TODO
SyscallDefinition(SyscallFunction::Fsync, "fsync", &[Fd, U32]), // TODO
SyscallDefinition(SyscallFunction::ReadAt, "read_at", &[Fd, U64, BytesMut]),
SyscallDefinition(SyscallFunction::WriteAt, "write_at", &[Fd, U64, Bytes]),
SyscallDefinition(
SyscallFunction::GetFileOption,
"get_file_option",
&[Fd, U32, BytesMut],
), // TODO
SyscallDefinition(
SyscallFunction::SetFileOption,
"set_file_option",
&[Fd, U32, Bytes],
), // TODO
SyscallDefinition(
SyscallFunction::OpenDirectory,
"open_directory",
&[OptionFd, Filename],
),
SyscallDefinition(
SyscallFunction::ReadDirectoryEntries,
"read_directory_entries",
&[Fd, Ptr, Size],
), // TODO
SyscallDefinition(
SyscallFunction::CreateDirectory,
"create_directory",
&[OptionFd, Filename, U32],
), // TODO
SyscallDefinition(
SyscallFunction::ReadLink,
"read_link",
&[OptionFd, Filename, BytesMut],
),
SyscallDefinition(
SyscallFunction::Remove,
"remove",
&[OptionFd, Filename, U32],
), // TODO
SyscallDefinition(SyscallFunction::Rename, "rename", &[Ptr]), // TODO
SyscallDefinition(SyscallFunction::CloneFd, "clone_fd", &[Fd, OptionFd]),
SyscallDefinition(
SyscallFunction::UpdateMetadata,
"update_metadata",
&[OptionFd, Filename, Ptr],
), // TODO
SyscallDefinition(
SyscallFunction::GetMetadata,
"get_metadata",
&[OptionFd, Filename, Ptr, U32],
), // TODO
SyscallDefinition(
SyscallFunction::DeviceRequest,
"device_request",
&[Fd, U32, BytesMut, Size],
), // TODO
SyscallDefinition(SyscallFunction::CreateTimer, "create_timer", &[U32]), // TODO
SyscallDefinition(SyscallFunction::CreatePid, "create_pid", &[Ptr, U32]), // TODO
SyscallDefinition(SyscallFunction::CreatePty, "create_pty", &[Ptr, Ptr, Ptr]), // TODO
SyscallDefinition(
SyscallFunction::CreateSharedMemory,
"create_shared_memory",
&[Size],
),
SyscallDefinition(
SyscallFunction::CreatePollChannel,
"create_poll_channel",
&[],
),
SyscallDefinition(SyscallFunction::CreatePipe, "create_pipe", &[Ptr]), // TODO
SyscallDefinition(
SyscallFunction::PollChannelWait,
"poll_channel_wait",
&[Fd, Ptr, U32, Ptr],
), // TODO
SyscallDefinition(
SyscallFunction::PollChannelControl,
"poll_channel_control",
&[Fd, U32, Fd],
), // TODO
// Network
SyscallDefinition(SyscallFunction::CreateSocket, "create_socket", &[U32]), // TODO
SyscallDefinition(SyscallFunction::Bind, "bind", &[Fd, Bytes]), // TODO
SyscallDefinition(SyscallFunction::Listen, "listen", &[Fd]),
SyscallDefinition(SyscallFunction::Connect, "connect", &[Fd, Bytes]), // TODO
SyscallDefinition(SyscallFunction::Accept, "accept", &[Fd, MaybePtr]), // TODO
SyscallDefinition(SyscallFunction::Shutdown, "shutdown", &[Fd, U32]), // TODO
SyscallDefinition(SyscallFunction::SendTo, "send_to", &[Fd, Bytes, MaybePtr]), // TODO
SyscallDefinition(
SyscallFunction::ReceiveFrom,
"receive_from",
&[Fd, BytesMut, MaybePtr],
), // TODO
SyscallDefinition(
SyscallFunction::GetSocketOption,
"get_socket_option",
&[Fd, U32, BytesMut],
), // TODO
SyscallDefinition(
SyscallFunction::SetSocketOption,
"set_socket_option",
&[Fd, U32, Bytes],
), // TODO
SyscallDefinition(SyscallFunction::SendMessage, "send_message", &[Fd, Ptr]), // TODO
SyscallDefinition(
SyscallFunction::ReceiveMessage,
"receive_message",
&[Fd, Ptr],
), // TODO
// C compat
SyscallDefinition(SyscallFunction::Fork, "fork", &[]),
SyscallDefinition(SyscallFunction::Execve, "execve", &[Ptr]), // TODO
// Debugging
SyscallDefinition(SyscallFunction::DebugTrace, "debug_trace", &[U32, Filename]), // TODO
SyscallDefinition(
SyscallFunction::DebugControl,
"debug_control",
&[U32, U32, BytesMut, Size],
), // TODO
]
};
impl SyscallDefinition {
fn parse(&self, args: &[u64]) -> Syscall {
let mut res = vec![];
let mut pos = 0;
for arg_def in self.2.iter() {
use SyscallArgument::*;
let (a, l) = match arg_def {
ArgType::MaybePtr => (MaybePtr(args[pos]), 1),
ArgType::Bytes => (Bytes(args[pos], args[pos + 1]), 2),
ArgType::BytesMut => (BytesMut(args[pos], args[pos + 1]), 2),
ArgType::Fd => (Fd(args[pos]), 1),
ArgType::OptionFd => (OptionFd(args[pos]), 1),
ArgType::Ptr => (Ptr(args[pos]), 1),
ArgType::Size => (Size(args[pos]), 1),
ArgType::U64 => (U64(args[pos]), 1),
ArgType::I64 => (I64(args[pos] as _), 1),
ArgType::U32 => (U32(args[pos] as _), 1),
ArgType::I32 => (I32(args[pos] as _), 1),
ArgType::PtrSystemTime => (PtrSystemTime(args[pos]), 1),
ArgType::ClockType => (ClockType(args[pos]), 1),
ArgType::Filename => (Filename(args[pos], args[pos + 1]), 2),
};
pos += l;
res.push(a);
}
Syscall(self.1, res)
}
}
pub fn parse_syscall(nr: u64, args: &[u64]) -> Option<Syscall> {
let func = SyscallFunction::try_from(nr as usize).ok()?;
let def = DEFS.iter().find(|e| e.0 == func)?;
Some(def.parse(args))
}
+51 -19
View File
@@ -1,36 +1,68 @@
#![feature(rustc_private, yggdrasil_os, let_chains)]
#![feature(rustc_private)]
use std::{
io,
process::{Command, ExitCode},
sync::atomic::{AtomicBool, Ordering},
};
use clap::Parser;
use tracer::CommandTracer;
use cross::{
process::{ChildTrace, CommandSpawnExt, TraceEvent},
signal,
};
pub mod format;
pub mod tracer;
use crate::definition::parse_syscall;
pub mod definition;
#[derive(Debug, Parser)]
struct Args {
command: String,
program: String,
args: Vec<String>,
}
fn run(args: &Args) -> io::Result<()> {
let mut command = Command::new(&args.command);
command.args(&args.args);
let tracer = CommandTracer::spawn(command)?;
tracer.run(format::format_syscall)
}
fn main() -> ExitCode {
let args = Args::parse();
match run(&args) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("{}: {error}", args.command);
ExitCode::FAILURE
static ABORT: AtomicBool = AtomicBool::new(false);
signal::set_sigint_handler(|| {
ABORT.store(true, Ordering::Release);
eprintln!("SIGINT");
});
let mut child = Command::new(args.program)
.args(args.args)
.spawn_with_trace()
.unwrap();
let mut last_syscall: Option<(u64, [u64; 6])> = None;
while !ABORT.load(Ordering::Relaxed) {
let event = child.next_event().unwrap();
match event {
TraceEvent::Exited => {
eprintln!("Exit");
break;
}
TraceEvent::SyscallExit(ret) => match last_syscall {
Some((nr, args)) => {
let call = parse_syscall(nr, &args);
if let Some(call) = call {
let mut s = String::new();
call.print(&mut s, &mut child);
eprintln!("{s} -> {ret}");
} else {
eprintln!("syscall {nr} {args:?} -> {ret}");
}
}
None => {
eprintln!("??? -> {ret}");
}
},
TraceEvent::SyscallEntry(nr, args) => {
last_syscall = Some((nr, args));
}
}
child.resume().ok();
}
ExitCode::SUCCESS
}
+24 -27
View File
@@ -29,38 +29,35 @@ const PROGRAMS: &[(&str, &str)] = &[
// shell
("shell", "bin/sh"),
// sysutils
("cat", "bin/cat"),
("chmod", "bin/chmod"),
("chroot", "sbin/chroot"),
("date", "bin/date"),
("dd", "bin/dd"),
("echo", "bin/echo"),
("env", "bin/env"),
("grep", "bin/grep"),
("hexd", "bin/hexd"),
("ln", "bin/ln"),
("login", "sbin/login"),
("ls", "bin/ls"),
("lspci", "bin/lspci"),
("md2txt", "bin/md2txt"),
("mkdir", "bin/mkdir"),
("mount", "sbin/mount"),
("mv", "bin/mv"),
("poweroff", "sbin/poweroff"),
("ps", "bin/ps"),
("random", "bin/random"),
("reboot", "sbin/reboot"),
("rm", "bin/rm"),
("sha256sum", "bin/sha256sum"),
("sleep", "bin/sleep"),
("chroot", "sbin/chroot"),
("login", "sbin/login"),
("strace", "bin/strace"),
("sync", "bin/sync"),
("sysmon", "bin/sysmon"),
("top", "bin/top"),
("ls", "bin/ls"),
("mv", "bin/mv"),
("ln", "bin/ln"),
("mkdir", "bin/mkdir"),
("touch", "bin/touch"),
("tree", "bin/tree"),
("tst", "bin/tst"),
("env", "bin/env"),
("rm", "bin/rm"),
("cat", "bin/cat"),
("hexd", "bin/hexd"),
("dd", "bin/dd"),
("random", "bin/random"),
("view", "bin/view"),
("grep", "bin/grep"),
("chmod", "bin/chmod"),
("sha256sum", "bin/sha256sum"),
("sysmon", "bin/sysmon"),
("date", "bin/date"),
("sync", "bin/sync"),
("sleep", "bin/sleep"),
("lspci", "bin/lspci"),
("ps", "bin/ps"),
("top", "bin/top"),
("tst", "bin/tst"),
("md2txt", "bin/md2txt"),
// netutils
("netconf", "sbin/netconf"),
("dhcp-client", "sbin/dhcp-client"),