Compare commits

...

2 Commits

7 changed files with 133 additions and 41 deletions

View File

@ -5,7 +5,9 @@ use acpi::HpetInfo;
use alloc::{collections::btree_map::BTreeMap, format, string::String, sync::Arc}; use alloc::{collections::btree_map::BTreeMap, format, string::String, sync::Arc};
use device_api::{ use device_api::{
device::{Device, DeviceInitContext}, device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, Irq, IrqOptions, IrqTrigger, IrqVector}, interrupt::{
InterruptAffinity, InterruptHandler, Irq, IrqOptions, IrqTrigger, IrqVector, MsiInfo,
},
}; };
use libk::{device::external_interrupt_controller, task::runtime, time}; use libk::{device::external_interrupt_controller, task::runtime, time};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
@ -16,7 +18,7 @@ use tock_registers::{
registers::{ReadOnly, ReadWrite}, registers::{ReadOnly, ReadWrite},
}; };
use crate::arch::x86::dummy_init_context; use crate::arch::{x86::dummy_init_context, x86_64::X86_64};
register_bitfields! { register_bitfields! {
u64, u64,
@ -49,7 +51,11 @@ register_bitfields! {
Edge = 0, Edge = 0,
Level = 1, Level = 1,
], ],
] ],
Tn_FSB_ROUTE [
Tn_FSB_INT_VAL OFFSET(0) NUMBITS(32) [],
Tn_FSB_INT_ADDR OFFSET(32) NUMBITS(32) [],
],
} }
register_structs! { register_structs! {
@ -72,7 +78,7 @@ register_structs! {
TimerRegs { TimerRegs {
(0x00 => Tn_CONFIG: ReadWrite<u64, Tn_CONFIG::Register>), (0x00 => Tn_CONFIG: ReadWrite<u64, Tn_CONFIG::Register>),
(0x08 => Tn_COMPARATOR: ReadWrite<u64>), (0x08 => Tn_COMPARATOR: ReadWrite<u64>),
(0x10 => Tn_FSB_ROUTE: ReadWrite<u64>), (0x10 => Tn_FSB_ROUTE: ReadWrite<u64, Tn_FSB_ROUTE::Register>),
(0x18 => _0), (0x18 => _0),
(0x20 => @END), (0x20 => @END),
} }
@ -136,30 +142,40 @@ impl Device for HpetTimer {
let regs = self.regs.write(); let regs = self.regs.write();
if regs.is_fsb_capable() { #[cfg(target_arch = "x86_64")]
log::warn!("TODO: HPET supports FSB interrupt delivery, but the kernel doesn't yet"); let irq = if regs.is_fsb_capable() {
} let lapic = X86_64::cpu_local_apic();
let msi_info = lapic.register_msi(InterruptAffinity::Any, self.clone())?;
log::info!(
"Set up {:?}, period={}t, periodic={}, msi mode",
self.name,
self.period,
self.periodic
);
let irq = regs.select_irq().ok_or(Error::InvalidArgument)?; IrqDestination::Fsb(msi_info)
} else {
let irq = regs.select_irq().ok_or(Error::InvalidArgument)?;
log::info!(
"Set up {:?}, period={}t, periodic={}, irq={:?}",
self.name,
self.period,
self.periodic,
irq
);
log::info!( intc.register_irq(
"Set up {:?}, period={}t, periodic={}, irq={:?}", irq,
self.name, IrqOptions {
self.period, trigger: IrqTrigger::Edge,
self.periodic, ..Default::default()
irq },
); self.clone(),
)?;
intc.enable_irq(irq)?;
intc.register_irq( IrqDestination::Irq(irq)
irq, };
IrqOptions {
trigger: IrqTrigger::Edge,
..Default::default()
},
self.clone(),
)?;
intc.enable_irq(irq)?;
let irq = IrqDestination::Irq(irq);
let now = self.parent.read_counter(); let now = self.parent.read_counter();
@ -216,6 +232,8 @@ impl HpetTimer {
let periodic = regs.is_periodic(); let periodic = regs.is_periodic();
let bits64 = regs.is_64_bit(); let bits64 = regs.is_64_bit();
log::info!("hpet{index}: periodic={periodic}, bits64={bits64}, period={period}");
let timer = Arc::new(HpetTimer { let timer = Arc::new(HpetTimer {
name: format!("hpet{index}"), name: format!("hpet{index}"),
regs: IrqSafeRwLock::new(regs), regs: IrqSafeRwLock::new(regs),
@ -235,14 +253,42 @@ impl Hpet {
fn new(base: PhysicalAddress) -> Result<Self, Error> { fn new(base: PhysicalAddress) -> Result<Self, Error> {
let regs = unsafe { DeviceMemoryIo::<GeneralRegs>::map(base, Default::default()) }?; let regs = unsafe { DeviceMemoryIo::<GeneralRegs>::map(base, Default::default()) }?;
let base_period = regs.timer_period(); let base_period = regs.timer_period();
// qemu: 100000000
// t430: 14318179
let base_frequency = FS_IN_S / base_period; let base_frequency = FS_IN_S / base_period;
Ok(Self {
let hpet = Self {
base, base,
base_period, base_period,
base_frequency, base_frequency,
regs: IrqSafeRwLock::new(regs), regs: IrqSafeRwLock::new(regs),
timers: IrqSafeRwLock::new(BTreeMap::new()), timers: IrqSafeRwLock::new(BTreeMap::new()),
}) };
hpet.test_timer_counts()?;
Ok(hpet)
}
fn test_timer_counts(&self) -> Result<(), Error> {
let regs = self.regs.write();
regs.stop();
for _ in 0..10000 {
core::hint::spin_loop();
}
let start = regs.counter();
regs.start();
for _ in 0..100000 {
core::hint::spin_loop();
}
regs.stop();
let now = regs.counter();
if now > start {
Ok(())
} else {
Err(Error::InvalidOperation)
}
} }
pub fn setup_from_acpi(acpi: &HpetInfo) -> Result<Arc<Self>, Error> { pub fn setup_from_acpi(acpi: &HpetInfo) -> Result<Arc<Self>, Error> {
@ -332,14 +378,28 @@ impl TimerRegs {
} }
fn enable(&self, irq: IrqDestination) { fn enable(&self, irq: IrqDestination) {
let config = match irq { match irq {
IrqDestination::Irq(Irq::External(irq)) => { IrqDestination::Irq(Irq::External(irq)) => {
Tn_CONFIG::Tn_INT_ROUTE_CNF.val(irq as u64) + Tn_CONFIG::Tn_INT_TYPE_CNF::Edge self.Tn_CONFIG.modify(
Tn_CONFIG::Tn_INT_ROUTE_CNF.val(irq as u64)
+ Tn_CONFIG::Tn_INT_TYPE_CNF::Edge
+ Tn_CONFIG::Tn_FSB_EN_CNF::CLEAR,
);
}
IrqDestination::Fsb(MsiInfo { address, value, .. }) => {
let address: u32 = address
.try_into()
.expect("FIXME: non-32-bit LAPIC MSI address");
self.Tn_CONFIG
.modify(Tn_CONFIG::Tn_INT_TYPE_CNF::Edge + Tn_CONFIG::Tn_FSB_EN_CNF::SET);
self.Tn_FSB_ROUTE.write(
Tn_FSB_ROUTE::Tn_FSB_INT_VAL.val(value as u64)
+ Tn_FSB_ROUTE::Tn_FSB_INT_ADDR.val(address as u64),
);
} }
_ => unreachable!(), _ => unreachable!(),
}; }
self.Tn_CONFIG.modify(config);
self.Tn_CONFIG.modify(Tn_CONFIG::Tn_INT_ENB_CNF::SET); self.Tn_CONFIG.modify(Tn_CONFIG::Tn_INT_ENB_CNF::SET);
} }
@ -396,4 +456,5 @@ impl GeneralRegs {
enum IrqDestination { enum IrqDestination {
Irq(Irq), Irq(Irq),
Fsb(MsiInfo),
} }

View File

@ -16,7 +16,7 @@ use kernel_arch_x86_64::{
table::{PageAttributes, PageEntry, PageTable, L1, L2, L3}, table::{PageAttributes, PageEntry, PageTable, L1, L2, L3},
EarlyMapping, MEMORY_LIMIT, RAM_MAPPING_L1, RAM_MAPPING_OFFSET, EarlyMapping, MEMORY_LIMIT, RAM_MAPPING_L1, RAM_MAPPING_OFFSET,
}, },
PerCpuData, LocalApicInterface, PerCpuData,
}; };
use libk::{ use libk::{
arch::Cpu, arch::Cpu,
@ -471,6 +471,10 @@ impl X86_64 {
Ok(()) Ok(())
} }
pub(crate) fn cpu_local_apic() -> Arc<dyn LocalApicInterface> {
Cpu::local().local_apic.clone()
}
} }
impl InitrdSource for LoadProtocolV1 { impl InitrdSource for LoadProtocolV1 {

View File

@ -2,7 +2,7 @@ pub use abi::io::{
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize, TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize,
}; };
use abi::{error::Error, io::RawFd}; use abi::{error::Error, io::RawFd, process::ProcessGroupId};
use super::device::{self, device_request}; use super::device::{self, device_request};
@ -33,6 +33,11 @@ pub fn set_terminal_size(fd: RawFd, size: &TerminalSize) -> Result<(), Error> {
device_request::<device::SetTerminalSize>(fd, &mut buffer, size) device_request::<device::SetTerminalSize>(fd, &mut buffer, size)
} }
pub fn set_terminal_group(fd: RawFd, group: ProcessGroupId) -> Result<(), Error> {
let mut buffer = [0; 8];
device_request::<device::SetTerminalGroup>(fd, &mut buffer, &group)
}
pub fn is_terminal(fd: RawFd) -> bool { pub fn is_terminal(fd: RawFd) -> bool {
let mut buffer = [0; 0]; let mut buffer = [0; 0];
device_request::<device::IsTerminal>(fd, &mut buffer, &()).is_ok() device_request::<device::IsTerminal>(fd, &mut buffer, &()).is_ok()

1
userspace/Cargo.lock generated
View File

@ -1396,6 +1396,7 @@ dependencies = [
"clap", "clap",
"cross", "cross",
"nom", "nom",
"runtime",
"thiserror", "thiserror",
] ]

View File

@ -11,5 +11,11 @@ thiserror.workspace = true
nom = "7.1.3" nom = "7.1.3"
[target.'cfg(target_os = "yggdrasil")'.dependencies]
runtime.workspace = true
[dev-dependencies]
runtime.workspace = true
[lints] [lints]
workspace = true workspace = true

View File

@ -1,14 +1,22 @@
use std::{ use std::{
fmt, fmt,
fs::File, fs::File,
io::{self, BufRead, BufReader, Stderr, Stdout, Write}, io::{self, stdin, BufRead, BufReader, Stderr, Stdout, Write},
marker::PhantomData, marker::PhantomData,
os::fd::{FromRawFd, IntoRawFd}, os::{
fd::{FromRawFd, IntoRawFd},
yggdrasil::{
io::terminal::set_terminal_group,
process::{create_process_group, CommandExt},
},
},
pipe::{PipeReader, PipeWriter}, pipe::{PipeReader, PipeWriter},
process::{self, Child, ExitCode, ExitStatus, Stdio}, process::{self, Child, ExitCode, ExitStatus, Stdio},
thread::{self, JoinHandle}, thread::{self, JoinHandle},
}; };
use runtime::rt::process::ProcessGroupId;
use crate::{builtin, env::Command, Error}; use crate::{builtin, env::Command, Error};
pub enum Outcome { pub enum Outcome {
@ -150,7 +158,7 @@ impl Outcome {
} }
// TODO move pipelines into process groups // TODO move pipelines into process groups
fn spawn_command(execution: Execution) -> Result<Child, Error> { fn spawn_command(execution: Execution, pgid: ProcessGroupId) -> Result<Child, Error> {
let mut command = process::Command::new(execution.program); let mut command = process::Command::new(execution.program);
command command
@ -159,6 +167,9 @@ fn spawn_command(execution: Execution) -> Result<Child, Error> {
.stdout(execution.stdout) .stdout(execution.stdout)
.stderr(execution.stderr); .stderr(execution.stderr);
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
command.process_group(pgid);
for (key, value) in execution.envs { for (key, value) in execution.envs {
command.env(key, value); command.env(key, value);
} }
@ -168,10 +179,10 @@ fn spawn_command(execution: Execution) -> Result<Child, Error> {
Ok(child) Ok(child)
} }
pub fn exec_pipeline<I: IntoIterator<Item = Execution>>( pub fn exec_pipeline<I: IntoIterator<Item = Execution>>(pipeline: I) -> Result<Vec<Handle>, Error> {
pipeline: I,
) -> Result<Vec<Handle>, Error> {
let mut handles = vec![]; let mut handles = vec![];
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
let pgid = create_process_group();
for element in pipeline.into_iter() { for element in pipeline.into_iter() {
let handle = if let Some(builtin) = builtin::get(&element.program) { let handle = if let Some(builtin) = builtin::get(&element.program) {
let io = builtin::Io { let io = builtin::Io {
@ -184,13 +195,17 @@ pub fn exec_pipeline<I: IntoIterator<Item = Execution>>(
builtin(io, element.arguments, element.envs.into()) builtin(io, element.arguments, element.envs.into())
})) }))
} else { } else {
let child = spawn_command(element)?; let child = spawn_command(element, pgid)?;
Handle::Process(child) Handle::Process(child)
}; };
handles.push(handle); handles.push(handle);
} }
#[cfg(any(target_os = "yggdrasil", rust_analyzer))]
unsafe {
set_terminal_group(&stdin(), pgid)?;
}
Ok(handles) Ok(handles)
} }

View File

@ -5,7 +5,7 @@
trait_alias, trait_alias,
exitcode_exit_method exitcode_exit_method
)] )]
#![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os))] #![cfg_attr(target_os = "yggdrasil", feature(yggdrasil_os, rustc_private))]
#![allow(clippy::new_without_default, clippy::should_implement_trait)] #![allow(clippy::new_without_default, clippy::should_implement_trait)]
use std::{ use std::{