mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 22:47:55 -05:00
properly shutdown system
This commit is contained in:
committed by
Matthew Leach
parent
504f7f01dc
commit
de76e243a2
@@ -1,7 +1,7 @@
|
||||
# Syscalls
|
||||
|
||||
| Number | Name | Signature | Symbol | Implemented |
|
||||
| ----------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- | ----------- |
|
||||
| ----------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------- |-------------|
|
||||
| 0x0 (0) | io_setup | (unsigned nr_events, aio_context_t *ctxp) | __arm64_sys_io_setup | false |
|
||||
| 0x1 (1) | io_destroy | (aio_context_t ctx) | __arm64_sys_io_destroy | false |
|
||||
| 0x2 (2) | io_submit | (aio_context_t ctx_id, long nr, struct iocb **iocbpp) | __arm64_sys_io_submit | false |
|
||||
@@ -78,7 +78,7 @@
|
||||
| 0x4b (75) | vmsplice | (int fd, const struct iovec *uiov, unsigned long nr_segs, unsigned int flags) | __arm64_sys_vmsplice | false |
|
||||
| 0x4c (76) | splice | (int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags) | __arm64_sys_splice | false |
|
||||
| 0x4d (77) | tee | (int fdin, int fdout, size_t len, unsigned int flags) | __arm64_sys_tee | false |
|
||||
| 0x4e (78) | readlinkat | (int dfd, const char *pathname, char *buf, int bufsiz) | __arm64_sys_readlinkat | dummy |
|
||||
| 0x4e (78) | readlinkat | (int dfd, const char *pathname, char *buf, int bufsiz) | __arm64_sys_readlinkat | dummy |
|
||||
| 0x4f (79) | newfstatat | (int dfd, const char *filename, struct stat *statbuf, int flag) | __arm64_sys_newfstatat | true |
|
||||
| 0x50 (80) | newfstat | (unsigned int fd, struct stat *statbuf) | __arm64_sys_newfstat | true |
|
||||
| 0x51 (81) | sync | () | __arm64_sys_sync | false |
|
||||
@@ -96,7 +96,7 @@
|
||||
| 0x5d (93) | exit | (int error_code) | __arm64_sys_exit | true |
|
||||
| 0x5e (94) | exit_group | (int error_code) | __arm64_sys_exit_group | true |
|
||||
| 0x5f (95) | waitid | (int which, pid_t upid, struct siginfo *infop, int options, struct rusage *ru) | __arm64_sys_waitid | false |
|
||||
| 0x60 (96) | set_tid_address | (int *tidptr) | __arm64_sys_set_tid_address | dummy |
|
||||
| 0x60 (96) | set_tid_address | (int *tidptr) | __arm64_sys_set_tid_address | dummy |
|
||||
| 0x61 (97) | unshare | (unsigned long unshare_flags) | __arm64_sys_unshare | false |
|
||||
| 0x62 (98) | futex | (u32 *uaddr, int op, u32 val, const struct __kernel_timespec *utime, u32 *uaddr2, u32 val3) | __arm64_sys_futex | false |
|
||||
| 0x63 (99) | set_robust_list | (struct robust_list_head *head, size_t len) | __arm64_sys_set_robust_list | false |
|
||||
@@ -129,7 +129,7 @@
|
||||
| 0x7e (126) | sched_get_priority_min | (int policy) | __arm64_sys_sched_get_priority_min | false |
|
||||
| 0x7f (127) | sched_rr_get_interval | (pid_t pid, struct __kernel_timespec *interval) | __arm64_sys_sched_rr_get_interval | false |
|
||||
| 0x80 (128) | restart_syscall | () | __arm64_sys_restart_syscall | false |
|
||||
| 0x81 (129) | kill | (pid_t pid, int sig) | __arm64_sys_kill | dummy |
|
||||
| 0x81 (129) | kill | (pid_t pid, int sig) | __arm64_sys_kill | dummy |
|
||||
| 0x82 (130) | tkill | (pid_t pid, int sig) | __arm64_sys_tkill | true |
|
||||
| 0x83 (131) | tgkill | (pid_t tgid, pid_t pid, int sig) | __arm64_sys_tgkill | false |
|
||||
| 0x84 (132) | sigaltstack | (const stack_t *uss, stack_t *uoss) | __arm64_sys_sigaltstack | true |
|
||||
@@ -142,7 +142,7 @@
|
||||
| 0x8b (139) | rt_sigreturn | () | __arm64_sys_rt_sigreturn | true |
|
||||
| 0x8c (140) | setpriority | (int which, int who, int niceval) | __arm64_sys_setpriority | false |
|
||||
| 0x8d (141) | getpriority | (int which, int who) | __arm64_sys_getpriority | false |
|
||||
| 0x8e (142) | reboot | (int magic1, int magic2, unsigned int cmd, void *arg) | __arm64_sys_reboot | false |
|
||||
| 0x8e (142) | reboot | (int magic1, int magic2, unsigned int cmd, void *arg) | __arm64_sys_reboot | partially |
|
||||
| 0x8f (143) | setregid | (gid_t rgid, gid_t egid) | __arm64_sys_setregid | false |
|
||||
| 0x90 (144) | setgid | (gid_t gid) | __arm64_sys_setgid | false |
|
||||
| 0x91 (145) | setreuid | (uid_t ruid, uid_t euid) | __arm64_sys_setreuid | false |
|
||||
|
||||
@@ -57,6 +57,14 @@ pub trait Filesystem: Send + Sync {
|
||||
|
||||
/// Returns the instance ID for this FS.
|
||||
fn id(&self) -> u64;
|
||||
|
||||
/// Flushes all pending data to the underlying storage device(s).
|
||||
///
|
||||
/// The default implementation is a no-op so that read-only filesystems do
|
||||
/// not need to override it.
|
||||
async fn sync(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// A unique identifier for an inode across the entire VFS. A tuple of
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use crate::{
|
||||
arch::{
|
||||
ArchImpl,
|
||||
arm64::boot::{
|
||||
arch_init_secondary,
|
||||
memory::{KERNEL_STACK_PG_ORDER, allocate_kstack_region},
|
||||
arm64::{
|
||||
boot::{
|
||||
arch_init_secondary,
|
||||
memory::{KERNEL_STACK_PG_ORDER, allocate_kstack_region},
|
||||
},
|
||||
psci::{PSCIEntry, PSCIMethod, boot_secondary_psci},
|
||||
},
|
||||
},
|
||||
drivers::{fdt_prober::get_fdt, timer::now},
|
||||
@@ -27,15 +30,12 @@ use libkernel::{
|
||||
},
|
||||
};
|
||||
use log::{info, warn};
|
||||
use psci::{PSCIEntry, PSCIMethod, boot_secondary_psci};
|
||||
|
||||
unsafe extern "C" {
|
||||
static __boot_stack: u8;
|
||||
static exception_return: u8;
|
||||
}
|
||||
|
||||
mod psci;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SecondaryBootInfo {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
use core::arch::naked_asm;
|
||||
use libkernel::memory::address::PA;
|
||||
|
||||
pub(super) struct PSCIEntry {
|
||||
pub method: PSCIMethod,
|
||||
pub cpu_on_id: Option<u32>,
|
||||
}
|
||||
|
||||
pub(super) enum PSCIMethod {
|
||||
Hvc,
|
||||
Smc,
|
||||
}
|
||||
|
||||
const CPU_ON_ID: u32 = 0xc400_0003;
|
||||
|
||||
pub(super) fn boot_secondary_psci(entry: PSCIEntry, core_id: usize, entry_fn: PA, ctx: PA) {
|
||||
let method_id = entry.cpu_on_id.unwrap_or(CPU_ON_ID);
|
||||
|
||||
match entry.method {
|
||||
PSCIMethod::Hvc => do_psci_hyp_call(
|
||||
method_id,
|
||||
core_id as _,
|
||||
entry_fn.value() as _,
|
||||
ctx.value() as _,
|
||||
),
|
||||
PSCIMethod::Smc => do_psci_smc_call(
|
||||
method_id,
|
||||
core_id as _,
|
||||
entry_fn.value() as _,
|
||||
ctx.value() as _,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
pub extern "C" fn do_psci_hyp_call(id: u32, arg1: u64, arg2: u64, arg3: u64) -> i64 {
|
||||
naked_asm!("hvc #0", "ret")
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
pub extern "C" fn do_psci_smc_call(id: u32, arg1: u64, arg2: u64, arg3: u64) -> i64 {
|
||||
naked_asm!("smc #0", "ret")
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::kernel::power::sys_reboot;
|
||||
use crate::{
|
||||
arch::{Arch, ArchImpl},
|
||||
clock::gettime::sys_clock_gettime,
|
||||
@@ -19,6 +20,7 @@ use crate::{
|
||||
seek::sys_lseek,
|
||||
splice::sys_sendfile,
|
||||
stat::sys_fstat,
|
||||
sync::sys_sync,
|
||||
},
|
||||
},
|
||||
kernel::uname::sys_uname,
|
||||
@@ -152,6 +154,7 @@ pub async fn handle_syscall() {
|
||||
.await
|
||||
}
|
||||
0x50 => sys_fstat(arg1.into(), TUA::from_value(arg2 as _)).await,
|
||||
0x51 => sys_sync().await,
|
||||
0x5d => sys_exit(arg1 as _),
|
||||
0x5e => sys_exit_group(arg1 as _),
|
||||
0x60 => sys_set_tid_address(VA::from_value(arg1 as _)).await,
|
||||
@@ -186,6 +189,7 @@ pub async fn handle_syscall() {
|
||||
|
||||
return;
|
||||
}
|
||||
0x8e => sys_reboot(arg1 as _, arg2 as _, arg3 as _, arg4 as _).await,
|
||||
0x94 => {
|
||||
sys_getresuid(
|
||||
TUA::from_value(arg1 as _),
|
||||
|
||||
@@ -34,6 +34,7 @@ mod exceptions;
|
||||
mod fdt;
|
||||
mod memory;
|
||||
mod proc;
|
||||
pub mod psci;
|
||||
|
||||
pub struct Aarch64 {}
|
||||
impl CpuOps for Aarch64 {
|
||||
@@ -108,6 +109,18 @@ impl Arch for Aarch64 {
|
||||
proc::idle::create_idle_task()
|
||||
}
|
||||
|
||||
fn power_off() -> ! {
|
||||
// Try PSCI `SYSTEM_OFF` first (works on QEMU `-machine virt` and most
|
||||
// real hardware that implements the PSCI interface).
|
||||
const PSCI_SYSTEM_OFF: u32 = 0x8400_0008;
|
||||
unsafe {
|
||||
psci::do_psci_hyp_call(PSCI_SYSTEM_OFF, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Fallback: halt the CPU indefinitely.
|
||||
Self::halt()
|
||||
}
|
||||
|
||||
unsafe fn copy_from_user(
|
||||
src: UA,
|
||||
dst: *mut (),
|
||||
|
||||
50
src/arch/arm64/psci.rs
Normal file
50
src/arch/arm64/psci.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use core::arch::naked_asm;
|
||||
use libkernel::memory::address::PA;
|
||||
|
||||
pub struct PSCIEntry {
|
||||
pub method: PSCIMethod,
|
||||
pub cpu_on_id: Option<u32>,
|
||||
}
|
||||
|
||||
pub enum PSCIMethod {
|
||||
Hvc,
|
||||
Smc,
|
||||
}
|
||||
|
||||
const CPU_ON_ID: u32 = 0xc400_0003;
|
||||
|
||||
// Re-export the low-level PSCI helpers so other modules (e.g. `arch::arm64::mod`)
|
||||
// can invoke them without repeating the `use` dance.
|
||||
|
||||
pub fn boot_secondary_psci(entry: PSCIEntry, core_id: usize, entry_fn: PA, ctx: PA) {
|
||||
let method_id = entry.cpu_on_id.unwrap_or(CPU_ON_ID);
|
||||
|
||||
match entry.method {
|
||||
PSCIMethod::Hvc => unsafe {
|
||||
do_psci_hyp_call(
|
||||
method_id,
|
||||
core_id as _,
|
||||
entry_fn.value() as _,
|
||||
ctx.value() as _,
|
||||
)
|
||||
},
|
||||
PSCIMethod::Smc => unsafe {
|
||||
do_psci_smc_call(
|
||||
method_id,
|
||||
core_id as _,
|
||||
entry_fn.value() as _,
|
||||
ctx.value() as _,
|
||||
)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
pub unsafe extern "C" fn do_psci_hyp_call(id: u32, arg1: u64, arg2: u64, arg3: u64) -> i64 {
|
||||
naked_asm!("hvc #0", "ret")
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
pub unsafe extern "C" fn do_psci_smc_call(id: u32, arg1: u64, arg2: u64, arg3: u64) -> i64 {
|
||||
naked_asm!("smc #0", "ret")
|
||||
}
|
||||
@@ -39,6 +39,9 @@ pub trait Arch: CpuOps + VirtualMemory {
|
||||
/// Construct a new idle task.
|
||||
fn create_idle_task() -> Task;
|
||||
|
||||
/// Powers off the machine. Implementations must never return.
|
||||
fn power_off() -> !;
|
||||
|
||||
/// Call a user-specified signal handler in the current process.
|
||||
fn do_signal(
|
||||
sig: SigId,
|
||||
|
||||
@@ -11,6 +11,7 @@ use reg::RegFile;
|
||||
|
||||
use crate::drivers::{DM, Driver};
|
||||
use crate::sync::SpinLock;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub mod dir;
|
||||
pub mod fops;
|
||||
@@ -316,3 +317,22 @@ impl VFS {
|
||||
}
|
||||
|
||||
pub static VFS: VFS = VFS::new();
|
||||
|
||||
impl VFS {
|
||||
/// Flushes all mounted filesystems and their underlying block devices.
|
||||
/// Any individual error is logged and ignored so that a single faulty
|
||||
/// filesystem does not block the shutdown sequence.
|
||||
pub async fn sync_all(&self) -> Result<()> {
|
||||
let filesystems: Vec<_> = {
|
||||
let state = self.state.lock_save_irq();
|
||||
state.filesystems.values().cloned().collect()
|
||||
};
|
||||
|
||||
for fs in filesystems {
|
||||
// Ignore per-filesystem errors; best-effort
|
||||
let _ = fs.sync().await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,3 +8,4 @@ pub mod rw;
|
||||
pub mod seek;
|
||||
pub mod splice;
|
||||
pub mod stat;
|
||||
pub mod sync;
|
||||
|
||||
6
src/fs/syscalls/sync.rs
Normal file
6
src/fs/syscalls/sync.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
use crate::fs::VFS;
|
||||
|
||||
pub async fn sys_sync() -> libkernel::error::Result<usize> {
|
||||
VFS.sync_all().await?;
|
||||
Ok(0)
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod kpipe;
|
||||
pub mod power;
|
||||
pub mod uname;
|
||||
|
||||
34
src/kernel/power.rs
Normal file
34
src/kernel/power.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use crate::{ArchImpl, arch::Arch};
|
||||
use libkernel::error::{KernelError, Result};
|
||||
|
||||
pub async fn sys_reboot(magic: u32, magic2: u32, op: u32, _arg: usize) -> Result<usize> {
|
||||
const LINUX_REBOOT_MAGIC1: u32 = 0xfee1_dead;
|
||||
const LINUX_REBOOT_MAGIC2: u32 = 672274793;
|
||||
const LINUX_REBOOT_MAGIC2A: u32 = 852072454;
|
||||
const LINUX_REBOOT_MAGIC2B: u32 = 369367448;
|
||||
const LINUX_REBOOT_MAGIC2C: u32 = 537993216;
|
||||
// const LINUX_REBOOT_CMD_CAD_OFF: u32 = 0x0000_0000;
|
||||
// const LINUX_REBOOT_CMD_CAD_ON: u32 = 0x89ab_cdef;
|
||||
// const LINUX_REBOOT_CMD_HALT: u32 = 0xcdef_0123;
|
||||
// const LINUX_REBOOT_CMD_KEXEC: u32 = 0x4558_4543;
|
||||
const LINUX_REBOOT_CMD_POWER_OFF: u32 = 0x4321_fedc;
|
||||
// const LINUX_REBOOT_CMD_RESTART: u32 = 0x0123_4567;
|
||||
// const LINUX_REBOOT_CMD_RESTART2: u32 = 0xa1b2_c3d4;
|
||||
// const LINUX_REBOOT_CMD_SW_SUSPEND: u32 = 0xd000_fce1;
|
||||
if magic != LINUX_REBOOT_MAGIC1
|
||||
|| (magic2 != LINUX_REBOOT_MAGIC2
|
||||
&& magic2 != LINUX_REBOOT_MAGIC2A
|
||||
&& magic2 != LINUX_REBOOT_MAGIC2B
|
||||
&& magic2 != LINUX_REBOOT_MAGIC2C)
|
||||
{
|
||||
return Err(KernelError::InvalidValue);
|
||||
}
|
||||
match op {
|
||||
LINUX_REBOOT_CMD_POWER_OFF => {
|
||||
// User is supposed to sync first.
|
||||
ArchImpl::power_off()
|
||||
}
|
||||
// TODO: Implement other reboot operations.
|
||||
_ => Err(KernelError::InvalidValue),
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use alloc::{
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use arch::ArchImpl;
|
||||
use arch::{Arch, ArchImpl};
|
||||
use core::panic::PanicInfo;
|
||||
use drivers::{fdt_prober::get_fdt, fs::register_fs_drivers};
|
||||
use fs::VFS;
|
||||
@@ -56,7 +56,7 @@ fn on_panic(info: &PanicInfo) -> ! {
|
||||
error!("Kernel panicked at unknown location: {panic_msg}");
|
||||
}
|
||||
|
||||
ArchImpl::halt();
|
||||
ArchImpl::power_off();
|
||||
}
|
||||
|
||||
async fn launch_init(opts: KOptions) {
|
||||
|
||||
Reference in New Issue
Block a user