Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6552fa8059 | |||
| 0ff48fd520 |
@@ -4,6 +4,8 @@ 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 {
|
||||
@@ -108,3 +110,9 @@ 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!()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#![feature(allocator_api)]
|
||||
#![feature(allocator_api, never_type)]
|
||||
#![no_std]
|
||||
|
||||
use acpi::AcpiTables;
|
||||
use acpi_system::{AcpiInterruptMethod, AcpiSystem};
|
||||
use acpi_system::{AcpiInterruptMethod, AcpiSleepState, AcpiSystem};
|
||||
use alloc::boxed::Box;
|
||||
use libk::error::Error;
|
||||
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
|
||||
@@ -45,6 +45,17 @@ 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
|
||||
@@ -67,12 +78,6 @@ 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,12 +1,12 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
|
||||
device::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: FullIrq,
|
||||
irq: IrqHandle,
|
||||
}
|
||||
|
||||
impl Io {
|
||||
@@ -164,14 +164,12 @@ impl Device for Pl011 {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
self.irq.register(self.clone())?;
|
||||
{
|
||||
let io = self.inner.get().output().io.lock();
|
||||
io.regs.IMSC.modify(IMSC::RXIM::SET);
|
||||
}
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.enable()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use device_api::{
|
||||
GpioController, GpioInterruptEvent, GpioInterruptMode, GpioPinLevel, PinHandle,
|
||||
SinglePinDirection,
|
||||
},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
@@ -17,7 +17,7 @@ use device_tree::{
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk::{device::external_interrupt_controller, event::signal_gpio_event};
|
||||
use libk::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: FullIrq,
|
||||
irq: IrqHandle,
|
||||
clocks: Vec<ClockHandle>,
|
||||
resets: Vec<ResetHandle>,
|
||||
gpio_events: [AtomicU64; 8],
|
||||
@@ -69,9 +69,8 @@ impl Device for Pl061 {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::ClockHandle,
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
debug::DebugSink,
|
||||
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
|
||||
device::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: FullIrq,
|
||||
irq: IrqHandle,
|
||||
clock: ClockHandle,
|
||||
inner: OneTimeInit<Arc<Terminal<Inner>>>,
|
||||
}
|
||||
@@ -171,9 +171,8 @@ impl Device for Bcm2835AuxUart {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
|
||||
let inner = self.inner.get().output();
|
||||
let regs = inner.regs.lock();
|
||||
|
||||
@@ -2,7 +2,7 @@ use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
gpio::{GpioController, GpioInterruptEvent, PinHandle},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{
|
||||
@@ -11,7 +11,6 @@ use device_tree::{
|
||||
},
|
||||
DeviceTreePropertyRead, TProp,
|
||||
};
|
||||
use libk::device::external_interrupt_controller;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tock_registers::{
|
||||
@@ -69,7 +68,7 @@ register_structs! {
|
||||
struct Bcm2711Gpio {
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
#[allow(unused)]
|
||||
irqs: [FullIrq; 2],
|
||||
irqs: [IrqHandle; 2],
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
@@ -142,10 +141,9 @@ impl Device for Bcm2711Gpio {
|
||||
regs.configure_pin_interrupts(pin, false, false, false, false);
|
||||
}
|
||||
|
||||
let intc = external_interrupt_controller()?;
|
||||
for irq in self.irqs.iter() {
|
||||
intc.register_irq(irq.irq, irq.options, self.clone())?;
|
||||
intc.enable_irq(irq.irq)?;
|
||||
irq.register(self.clone())?;
|
||||
irq.enable()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -2,8 +2,8 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
|
||||
InterruptTable, Irq, IrqOptions, IrqVector,
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
|
||||
IrqHandle, IrqOptions, IrqVector,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
@@ -261,9 +261,9 @@ impl Device for Plic {
|
||||
}
|
||||
|
||||
impl DeviceTreeInterruptController for Plic {
|
||||
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
|
||||
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<IrqHandle> {
|
||||
let num = property.read_cell(offset, 1)?;
|
||||
Some(FullIrq {
|
||||
Some(IrqHandle {
|
||||
irq: Irq::External(num as _),
|
||||
options: IrqOptions::default(),
|
||||
})
|
||||
|
||||
@@ -8,14 +8,13 @@ use device_api::{
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
dma::DmaAllocator,
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, 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},
|
||||
@@ -68,7 +67,7 @@ struct Stmmac {
|
||||
rst_stmmaceth: ResetHandle,
|
||||
rst_ahb: ResetHandle,
|
||||
|
||||
irq: FullIrq,
|
||||
irq: IrqHandle,
|
||||
softirq_events: BitmapEvent<AtomicWaker>,
|
||||
|
||||
inner: OneTimeInit<Inner>,
|
||||
@@ -184,9 +183,7 @@ impl Device for Stmmac {
|
||||
}
|
||||
let dma = self.dma.init(cx.dma_allocator.clone());
|
||||
|
||||
let intc = external_interrupt_controller()?;
|
||||
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
self.irq.register(self.clone())?;
|
||||
|
||||
let tx_ring_capacity = 32;
|
||||
let rx_ring_capacity = 32;
|
||||
@@ -350,7 +347,7 @@ impl Device for Stmmac {
|
||||
ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone());
|
||||
self.iface_id.init(iface.id());
|
||||
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.enable()?;
|
||||
|
||||
let p = self.clone();
|
||||
runtime::spawn(async move { p.softirq().await })?;
|
||||
|
||||
@@ -3,10 +3,11 @@ use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::device::Device;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct FullIrq {
|
||||
#[derive(Clone)]
|
||||
pub struct IrqHandle {
|
||||
pub irq: Irq,
|
||||
pub options: IrqOptions,
|
||||
pub intc: Arc<dyn ExternalInterruptController>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -154,6 +155,16 @@ 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::FullIrq,
|
||||
interrupt::IrqHandle,
|
||||
};
|
||||
use fdt_rs::spec::Phandle;
|
||||
|
||||
@@ -83,14 +83,14 @@ pub fn map_interrupt_at(
|
||||
interrupt_controller: &Arc<Node>,
|
||||
property: &TProp,
|
||||
offset: usize,
|
||||
) -> Option<FullIrq> {
|
||||
) -> Option<IrqHandle> {
|
||||
let interrupt_controller = interrupt_controller.interrupt_controller.try_get()?;
|
||||
interrupt_controller.map_interrupt(property, offset)
|
||||
interrupt_controller.clone().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<FullIrq> {
|
||||
pub fn map_interrupt(phandle: Phandle, property: &TProp, index: usize) -> Option<IrqHandle> {
|
||||
let interrupt_controller = lookup_phandle(phandle, true)?;
|
||||
let interrupt_cells = interrupt_controller.self_interrupt_cells()?;
|
||||
map_interrupt_at(&interrupt_controller, property, index * interrupt_cells)
|
||||
|
||||
@@ -7,7 +7,7 @@ use device_api::{
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
device::Device,
|
||||
gpio::PinHandle,
|
||||
interrupt::{ExternalInterruptController, FullIrq},
|
||||
interrupt::{ExternalInterruptController, IrqHandle},
|
||||
};
|
||||
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, property: &TProp, offset: usize) -> Option<FullIrq>;
|
||||
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle>;
|
||||
|
||||
/// Returns the [ExternalInterruptController] implementor of this node
|
||||
fn as_interrupt_controller(self: Arc<Self>) -> Arc<dyn ExternalInterruptController>;
|
||||
|
||||
@@ -10,7 +10,7 @@ use device_api::{
|
||||
clock::{ClockController, ClockHandle, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
gpio::PinHandle,
|
||||
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
|
||||
interrupt::{ExternalInterruptController, IrqHandle, 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<FullIrq> {
|
||||
pub fn interrupt(&self, index: usize) -> Option<IrqHandle> {
|
||||
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<FullIrq> {
|
||||
pub fn interrupt_from(&self, property: &TProp, index: usize) -> Option<IrqHandle> {
|
||||
let phandle = self.interrupt_parent?;
|
||||
map_interrupt(phandle, property, index)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
gpio::{GpioPinConfig, GpioPinLevel, InputPinBias, OutputPinBias},
|
||||
interrupt::{FullIrq, MessageInterruptController},
|
||||
interrupt::{IrqHandle, MessageInterruptController},
|
||||
};
|
||||
use fdt_rs::prelude::PropReader;
|
||||
use yggdrasil_abi::net::MacAddress;
|
||||
@@ -44,7 +44,6 @@ 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,
|
||||
@@ -57,7 +56,7 @@ pub struct PcieInterruptEntry {
|
||||
/// Destination interrupt controller
|
||||
pub interrupt_controller: Arc<Node>,
|
||||
/// Destination IRQ options
|
||||
pub irq: FullIrq,
|
||||
pub irq: IrqHandle,
|
||||
}
|
||||
|
||||
/// Represents a single PCI address (Requester ID for a MSI(-x))
|
||||
|
||||
@@ -310,6 +310,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
|
||||
}
|
||||
|
||||
fn irq_common() {
|
||||
// TODO some concept of "root" interrupt controller
|
||||
external_interrupt_controller()
|
||||
.unwrap()
|
||||
.handle_pending_irqs();
|
||||
|
||||
@@ -8,9 +8,9 @@ use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{
|
||||
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
|
||||
InterruptTable, IpiDeliveryTarget, IpiMessage, Irq, IrqLevel, IrqOptions, IrqTrigger,
|
||||
IrqVector, LocalInterruptController,
|
||||
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable,
|
||||
IpiDeliveryTarget, IpiMessage, Irq, IrqHandle, IrqLevel, IrqOptions, IrqTrigger, IrqVector,
|
||||
LocalInterruptController,
|
||||
},
|
||||
};
|
||||
use device_tree::{
|
||||
@@ -141,8 +141,9 @@ impl ExternalInterruptController for Gic {
|
||||
gicc.clear_irq(irq_number);
|
||||
|
||||
if irq_number == IPI_VECTOR as usize {
|
||||
// TODO pop entry
|
||||
crate::panic::panic_secondary();
|
||||
let ipi = Cpu::local().get_ipi();
|
||||
AArch64::handle_ipi(ipi);
|
||||
return;
|
||||
}
|
||||
|
||||
if irq_number < GIC_PPI_START as usize {
|
||||
@@ -203,7 +204,7 @@ impl LocalInterruptController for Gic {
|
||||
}
|
||||
|
||||
impl DeviceTreeInterruptController for Gic {
|
||||
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
|
||||
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle> {
|
||||
// IRQ_TYPE_NONE - 0
|
||||
// IRQ_TYPE_EDGE_RISING - 1
|
||||
// IRQ_TYPE_EDGE_FALLING - 2
|
||||
@@ -229,9 +230,10 @@ impl DeviceTreeInterruptController for Gic {
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(FullIrq {
|
||||
Some(IrqHandle {
|
||||
irq,
|
||||
options: IrqOptions { trigger, level },
|
||||
intc: self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,15 @@ use core::sync::atomic::{self, Ordering};
|
||||
use aarch64_cpu::registers::{CNTP_CTL_EL0, CNTP_TVAL_EL0};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
interrupt::{Irq, LocalInterruptController},
|
||||
interrupt::{IpiDeliveryTarget, IpiMessage, Irq, LocalInterruptController},
|
||||
ResetDevice,
|
||||
};
|
||||
use device_tree::{
|
||||
driver::{unflatten_device_tree, InitSequence},
|
||||
DeviceTree, DeviceTreeNodeExt,
|
||||
};
|
||||
use kernel_arch_aarch64::{mem, ArchitectureImpl, PerCpuData};
|
||||
use kernel_arch::Architecture;
|
||||
use kernel_arch_aarch64::{mem, ArchitectureImpl, PerCpuData, CPU_COUNT};
|
||||
use libk::{arch::Cpu, config, debug, device::external_interrupt_controller, error::Error};
|
||||
use libk_mm::{
|
||||
address::PhysicalAddress,
|
||||
@@ -20,7 +21,7 @@ use libk_mm::{
|
||||
pointer::PhysicalRef,
|
||||
table::EntryLevelExt,
|
||||
};
|
||||
use libk_util::OneTimeInit;
|
||||
use libk_util::{sync::SpinFence, OneTimeInit};
|
||||
use tock_registers::interfaces::Writeable;
|
||||
use ygg_driver_pci::PciBusManager;
|
||||
|
||||
@@ -28,6 +29,7 @@ use crate::{
|
||||
arch::{aarch64::gic::Gic, Platform},
|
||||
device::{power::arm_psci::Psci, MACHINE_NAME},
|
||||
fs::{Initrd, INITRD_DATA},
|
||||
panic,
|
||||
util::call_init_array,
|
||||
};
|
||||
|
||||
@@ -68,6 +70,8 @@ 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() {
|
||||
@@ -96,6 +100,18 @@ 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 {
|
||||
@@ -103,6 +119,41 @@ 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,
|
||||
|
||||
@@ -7,16 +7,16 @@ use abi::{error::Error, time::NANOSECONDS_IN_SECOND};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use kernel_arch::task::Scheduler;
|
||||
use libk::{arch::Cpu, device::external_interrupt_controller, task::runtime, time};
|
||||
use libk::{arch::Cpu, task::runtime, time};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
|
||||
/// ARM Generic Timer driver
|
||||
pub struct ArmTimer {
|
||||
irq: FullIrq,
|
||||
irq: IrqHandle,
|
||||
}
|
||||
|
||||
/// ARM timer tick interval (in some time units?)
|
||||
@@ -63,14 +63,12 @@ impl Device for ArmTimer {
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
log::info!("ARM Generic Timer frequency={}Hz", CNTFRQ_EL0.get());
|
||||
|
||||
let intc = external_interrupt_controller()?;
|
||||
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
self.irq.register(self.clone())?;
|
||||
|
||||
CNTP_CTL_EL0.modify(CNTP_CTL_EL0::IMASK::CLEAR);
|
||||
CNTP_TVAL_EL0.set(TICK_INTERVAL);
|
||||
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.enable()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -82,7 +80,7 @@ impl ArmTimer {
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure the function has not been called before.
|
||||
pub const unsafe fn new(irq: FullIrq) -> Self {
|
||||
pub const unsafe fn new(irq: IrqHandle) -> Self {
|
||||
Self { irq }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Provides architecture/platform-specific implementation details
|
||||
|
||||
use abi::error::Error;
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
|
||||
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
|
||||
@@ -51,6 +52,19 @@ 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)
|
||||
|
||||
@@ -11,7 +11,7 @@ use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use kernel_arch_riscv64::{
|
||||
mem,
|
||||
registers::{SIE, SSTATUS},
|
||||
PerCpuData,
|
||||
sbi, PerCpuData,
|
||||
};
|
||||
use libk::{arch::Cpu, config};
|
||||
use libk_mm::{
|
||||
@@ -51,6 +51,10 @@ 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
|
||||
|
||||
@@ -11,6 +11,8 @@ use libk::{
|
||||
};
|
||||
use static_assertions::{const_assert, const_assert_eq};
|
||||
|
||||
use crate::arch::x86_64::X86_64;
|
||||
|
||||
use super::exception;
|
||||
|
||||
pub mod ioapic;
|
||||
@@ -115,8 +117,8 @@ unsafe extern "C" fn dummy_irq_handler() {
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ipi_handler() {
|
||||
let cpu = Cpu::local();
|
||||
todo!("Processor {} received an IPI", cpu.id());
|
||||
let ipi = Cpu::local().get_ipi();
|
||||
X86_64::handle_ipi(ipi);
|
||||
}
|
||||
|
||||
global_asm!(
|
||||
|
||||
@@ -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::task::thread::Thread;
|
||||
use libk::{arch::Cpu, 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;
|
||||
use crate::arch::x86_64::{apic, X86_64};
|
||||
|
||||
primitive_enum! {
|
||||
enum ExceptionKind: u64 {
|
||||
@@ -231,7 +231,13 @@ extern "C" fn __x86_64_exception_handler(frame: *mut ExceptionFrame) {
|
||||
}
|
||||
|
||||
extern "C" fn __x86_64_nmi_handler() -> ! {
|
||||
crate::panic::panic_secondary();
|
||||
let ipi = Cpu::local().get_ipi();
|
||||
if let Some(ipi) = ipi {
|
||||
X86_64::handle_ipi(Some(ipi));
|
||||
unreachable!();
|
||||
} else {
|
||||
panic!("Spurious/unknown NMI received");
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the interrupt descriptor table for the given CPU.
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
//! x86-64 architecture implementation
|
||||
|
||||
use core::ptr::null_mut;
|
||||
use core::{ptr::null_mut, sync::atomic::Ordering};
|
||||
|
||||
use abi::error::Error;
|
||||
use acpi::{mcfg::Mcfg, AcpiTables, HpetInfo, InterruptModel};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::device::Device;
|
||||
use device_api::{
|
||||
device::Device,
|
||||
interrupt::{IpiDeliveryTarget, IpiMessage},
|
||||
};
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
use kernel_arch_x86::{
|
||||
cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures, ExtEdxFeatures},
|
||||
gdt,
|
||||
};
|
||||
use kernel_arch_x86_64::{mem, LocalApicInterface, PerCpuData};
|
||||
use kernel_arch_x86_64::{mem, LocalApicInterface, PerCpuData, CPU_COUNT};
|
||||
use libk::{
|
||||
arch::Cpu,
|
||||
config, debug,
|
||||
@@ -27,7 +31,10 @@ use libk_mm::{
|
||||
pointer::PhysicalRef,
|
||||
table::EntryLevel,
|
||||
};
|
||||
use libk_util::OneTimeInit;
|
||||
use libk_util::{
|
||||
sync::{IrqGuard, SpinFence},
|
||||
OneTimeInit,
|
||||
};
|
||||
use yboot_proto::{
|
||||
v1::{self, AvailableMemoryRegion},
|
||||
LoadProtocolV1,
|
||||
@@ -45,6 +52,7 @@ use crate::{
|
||||
Platform,
|
||||
},
|
||||
device::display::linear_fb::LinearFramebuffer,
|
||||
panic,
|
||||
util::call_init_array,
|
||||
};
|
||||
|
||||
@@ -72,7 +80,9 @@ 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() {
|
||||
@@ -87,9 +97,42 @@ 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) => {
|
||||
@@ -196,6 +239,12 @@ 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(())
|
||||
|
||||
@@ -61,6 +61,7 @@ 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 {
|
||||
@@ -74,6 +75,12 @@ 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! {
|
||||
|
||||
@@ -3,7 +3,7 @@ use abi::{error::Error, io::TerminalOptions};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
@@ -79,7 +79,7 @@ struct Inner {
|
||||
pub struct Ns16550a {
|
||||
inner: OneTimeInit<Arc<Terminal<Inner>>>,
|
||||
base: PhysicalAddress,
|
||||
irq: FullIrq,
|
||||
irq: IrqHandle,
|
||||
}
|
||||
|
||||
impl Io {
|
||||
@@ -135,9 +135,8 @@ impl Device for Ns16550a {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
let io = self.inner.get().output().io.lock();
|
||||
io.regs.IER.modify(IER::RDR::SET);
|
||||
Ok(())
|
||||
|
||||
@@ -4,7 +4,7 @@ use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, Hertz, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
interrupt::{InterruptHandler, IrqHandle, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::{
|
||||
@@ -110,7 +110,7 @@ struct Inner {
|
||||
/// Synopsys DesignWare 8250 UART
|
||||
pub struct DwUart {
|
||||
base: PhysicalAddress,
|
||||
irq: FullIrq,
|
||||
irq: IrqHandle,
|
||||
clk_baud: ClockHandle,
|
||||
#[allow(unused)]
|
||||
clk_apb: Option<ClockHandle>,
|
||||
@@ -241,9 +241,8 @@ impl Device for DwUart {
|
||||
}
|
||||
|
||||
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
|
||||
let intc = external_interrupt_controller()?;
|
||||
intc.register_irq(self.irq.irq, Default::default(), self.clone())?;
|
||||
intc.enable_irq(self.irq.irq)?;
|
||||
self.irq.register(self.clone())?;
|
||||
self.irq.enable()?;
|
||||
|
||||
let output = self.inner.get().output();
|
||||
let io = output.io.lock();
|
||||
|
||||
@@ -75,8 +75,10 @@ cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "x86_64")] {
|
||||
extern crate ygg_driver_net_igbe;
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
extern crate ygg_driver_bsp_arm;
|
||||
extern crate ygg_driver_bsp_bcm283x;
|
||||
} else if #[cfg(target_arch = "riscv64")] {
|
||||
extern crate ygg_driver_bsp_riscv;
|
||||
extern crate ygg_driver_bsp_jh7110;
|
||||
|
||||
extern crate ygg_driver_net_stmmac;
|
||||
|
||||
@@ -16,7 +16,7 @@ use abi::{
|
||||
option::OptionValue,
|
||||
path::Path,
|
||||
process::{ExecveOptions, ProcessId},
|
||||
system::{self, SystemInfoVariant},
|
||||
system::{self, SystemControlVariant, SystemInfoVariant},
|
||||
time::{ClockType, SystemTime},
|
||||
};
|
||||
use libk::{
|
||||
@@ -26,7 +26,10 @@ use libk::{
|
||||
};
|
||||
use libk_mm::phys;
|
||||
|
||||
use crate::fs;
|
||||
use crate::{
|
||||
arch::{Platform, PLATFORM},
|
||||
fs,
|
||||
};
|
||||
|
||||
use super::run_with_io;
|
||||
|
||||
@@ -86,6 +89,16 @@ 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 {
|
||||
|
||||
@@ -80,6 +80,7 @@ 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>;
|
||||
|
||||
|
||||
@@ -21,6 +21,14 @@ 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,7 +1,10 @@
|
||||
//! System-related parameters
|
||||
|
||||
pub use abi::system::*;
|
||||
use abi::{error::Error, option::OptionValue};
|
||||
use abi::{
|
||||
error::Error,
|
||||
option::{OptionValue, RequestValue},
|
||||
};
|
||||
|
||||
/// Helper macro for [get_system_info]
|
||||
pub macro get_system_info($variant_ty:ty) {{
|
||||
@@ -14,3 +17,13 @@ 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])
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ yggdrasil-abi.workspace = true
|
||||
yggdrasil-rt.workspace = true
|
||||
runtime.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
runtime.workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
@@ -41,6 +44,14 @@ 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"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#![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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
fn main() {}
|
||||
@@ -29,35 +29,37 @@ const PROGRAMS: &[(&str, &str)] = &[
|
||||
// shell
|
||||
("shell", "bin/sh"),
|
||||
// sysutils
|
||||
("echo", "bin/echo"),
|
||||
("mount", "sbin/mount"),
|
||||
("chroot", "sbin/chroot"),
|
||||
("login", "sbin/login"),
|
||||
("strace", "bin/strace"),
|
||||
("ls", "bin/ls"),
|
||||
("mv", "bin/mv"),
|
||||
("ln", "bin/ln"),
|
||||
("mkdir", "bin/mkdir"),
|
||||
("touch", "bin/touch"),
|
||||
("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"),
|
||||
("chroot", "sbin/chroot"),
|
||||
("date", "bin/date"),
|
||||
("sync", "bin/sync"),
|
||||
("sleep", "bin/sleep"),
|
||||
("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"),
|
||||
("ps", "bin/ps"),
|
||||
("top", "bin/top"),
|
||||
("tst", "bin/tst"),
|
||||
("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"),
|
||||
("strace", "bin/strace"),
|
||||
("sync", "bin/sync"),
|
||||
("sysmon", "bin/sysmon"),
|
||||
("top", "bin/top"),
|
||||
("touch", "bin/touch"),
|
||||
("tst", "bin/tst"),
|
||||
("view", "bin/view"),
|
||||
// netutils
|
||||
("netconf", "sbin/netconf"),
|
||||
("dhcp-client", "sbin/dhcp-client"),
|
||||
|
||||
Reference in New Issue
Block a user