Compare commits
2 Commits
de16799908
...
975df985ac
Author | SHA1 | Date | |
---|---|---|---|
975df985ac | |||
a0cdc39f30 |
@ -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),
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
1
userspace/Cargo.lock
generated
@ -1396,6 +1396,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"cross",
|
"cross",
|
||||||
"nom",
|
"nom",
|
||||||
|
"runtime",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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::{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user