diff options
author | Liav A <liavalb@gmail.com> | 2021-09-11 12:20:47 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-09-12 11:52:16 +0200 |
commit | 8d0dbdeaac4fa1d38ce9b1c467fc3865fb3685e2 (patch) | |
tree | ae33d3b978c4141fef463c78ce75ad217f7f8520 /Kernel | |
parent | 06e95d0fd74a93858e5f4d0e1d32e92631e649ff (diff) | |
download | serenity-8d0dbdeaac4fa1d38ce9b1c467fc3865fb3685e2.zip |
Kernel+Userland: Introduce a new way to reboot and poweroff the machine
This change removes the halt and reboot syscalls, and create a new
mechanism to change the power state of the machine.
Instead of how power state was changed until now, put a SysFS node as
writable only for the superuser, that with a defined value, can result
in either reboot or poweroff.
In the future, a power group can be assigned to this node (which will be
the GroupID responsible for power management).
This opens an opportunity to permit to shutdown/reboot without superuser
permissions, so in the future, a userspace daemon can take control of
this node to perform power management operations without superuser
permissions, if we enforce different UserID/GroupID on that node.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/API/Syscall.h | 2 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Kernel/Firmware/PowerStateSwitch.cpp | 99 | ||||
-rw-r--r-- | Kernel/Firmware/PowerStateSwitch.h | 36 | ||||
-rw-r--r-- | Kernel/Firmware/SysFSFirmware.cpp | 3 | ||||
-rw-r--r-- | Kernel/Process.h | 2 | ||||
-rw-r--r-- | Kernel/Syscalls/shutdown.cpp | 61 |
7 files changed, 139 insertions, 66 deletions
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index d590ab5125..955ce205f8 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -106,7 +106,6 @@ enum class NeedsBigProcessLock { S(getsockopt, NeedsBigProcessLock::Yes) \ S(gettid, NeedsBigProcessLock::No) \ S(getuid, NeedsBigProcessLock::Yes) \ - S(halt, NeedsBigProcessLock::Yes) \ S(inode_watcher_add_watch, NeedsBigProcessLock::Yes) \ S(inode_watcher_remove_watch, NeedsBigProcessLock::Yes) \ S(ioctl, NeedsBigProcessLock::Yes) \ @@ -144,7 +143,6 @@ enum class NeedsBigProcessLock { S(readlink, NeedsBigProcessLock::Yes) \ S(readv, NeedsBigProcessLock::Yes) \ S(realpath, NeedsBigProcessLock::Yes) \ - S(reboot, NeedsBigProcessLock::Yes) \ S(recvfd, NeedsBigProcessLock::Yes) \ S(recvmsg, NeedsBigProcessLock::Yes) \ S(rename, NeedsBigProcessLock::Yes) \ diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index d48cf46faf..eb045e5843 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -127,6 +127,7 @@ set(KERNEL_SOURCES Firmware/ACPI/MultiProcessorParser.cpp Firmware/ACPI/Parser.cpp Firmware/BIOS.cpp + Firmware/PowerStateSwitch.cpp Firmware/SysFSFirmware.cpp FutexQueue.cpp Interrupts/APIC.cpp @@ -241,7 +242,6 @@ set(KERNEL_SOURCES Syscalls/sendfd.cpp Syscalls/setpgid.cpp Syscalls/setuid.cpp - Syscalls/shutdown.cpp Syscalls/sigaction.cpp Syscalls/socket.cpp Syscalls/stat.cpp diff --git a/Kernel/Firmware/PowerStateSwitch.cpp b/Kernel/Firmware/PowerStateSwitch.cpp new file mode 100644 index 0000000000..1bed8bffbe --- /dev/null +++ b/Kernel/Firmware/PowerStateSwitch.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/FileSystem/FileSystem.h> +#include <Kernel/Firmware/ACPI/Parser.h> +#include <Kernel/Firmware/PowerStateSwitch.h> +#include <Kernel/IO.h> +#include <Kernel/Process.h> +#include <Kernel/Sections.h> +#include <Kernel/TTY/ConsoleManagement.h> + +namespace Kernel { + +mode_t PowerStateSwitchNode::permissions() const +{ + return S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; +} + +UNMAP_AFTER_INIT NonnullRefPtr<PowerStateSwitchNode> PowerStateSwitchNode::must_create(FirmwareSysFSDirectory& firmware_directory) +{ + return adopt_ref_if_nonnull(new (nothrow) PowerStateSwitchNode(firmware_directory)).release_nonnull(); +} + +UNMAP_AFTER_INIT PowerStateSwitchNode::PowerStateSwitchNode(FirmwareSysFSDirectory&) + : SysFSComponent("power_state") +{ +} + +KResultOr<size_t> PowerStateSwitchNode::write_bytes(off_t offset, size_t count, UserOrKernelBuffer const& data, OpenFileDescription*) +{ + if (Checked<off_t>::addition_would_overflow(offset, count)) + return EOVERFLOW; + if (offset > 0) + return EINVAL; + if (count > 1) + return EINVAL; + + char buf[1]; + TRY(data.read(buf, 1)); + switch (buf[0]) { + case '0': + return EINVAL; + case '1': + reboot(); + VERIFY_NOT_REACHED(); + case '2': + poweroff(); + VERIFY_NOT_REACHED(); + default: + return EINVAL; + } + VERIFY_NOT_REACHED(); +} + +void PowerStateSwitchNode::reboot() +{ + MutexLocker locker(Process::current().big_lock()); + + dbgln("acquiring FS locks..."); + FileSystem::lock_all(); + dbgln("syncing mounted filesystems..."); + FileSystem::sync(); + dbgln("attempting reboot via ACPI"); + if (ACPI::is_enabled()) + ACPI::Parser::the()->try_acpi_reboot(); + dbgln("attempting reboot via KB Controller..."); + IO::out8(0x64, 0xFE); + dbgln("reboot attempts failed, applications will stop responding."); + dmesgln("Reboot can't be completed. It's safe to turn off the computer!"); + Processor::halt(); +} + +void PowerStateSwitchNode::poweroff() +{ + MutexLocker locker(Process::current().big_lock()); + + ConsoleManagement::the().switch_to_debug(); + + dbgln("acquiring FS locks..."); + FileSystem::lock_all(); + dbgln("syncing mounted filesystems..."); + FileSystem::sync(); + dbgln("attempting system shutdown..."); + // QEMU Shutdown + IO::out16(0x604, 0x2000); + // If we're here, the shutdown failed. Try VirtualBox shutdown. + IO::out16(0x4004, 0x3400); + // VirtualBox shutdown failed. Try Bochs/Old QEMU shutdown. + IO::out16(0xb004, 0x2000); + dbgln("shutdown attempts failed, applications will stop responding."); + dmesgln("Shutdown can't be completed. It's safe to turn off the computer!"); + Processor::halt(); +} + +} diff --git a/Kernel/Firmware/PowerStateSwitch.h b/Kernel/Firmware/PowerStateSwitch.h new file mode 100644 index 0000000000..e96540f202 --- /dev/null +++ b/Kernel/Firmware/PowerStateSwitch.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/RefPtr.h> +#include <AK/Types.h> +#include <AK/Vector.h> +#include <Kernel/FileSystem/SysFS.h> +#include <Kernel/Firmware/SysFSFirmware.h> +#include <Kernel/KBuffer.h> +#include <Kernel/Memory/MappedROM.h> +#include <Kernel/Memory/Region.h> +#include <Kernel/PhysicalAddress.h> +#include <Kernel/VirtualAddress.h> + +namespace Kernel { + +class PowerStateSwitchNode final : public SysFSComponent { +public: + static NonnullRefPtr<PowerStateSwitchNode> must_create(FirmwareSysFSDirectory&); + virtual mode_t permissions() const override; + virtual KResultOr<size_t> write_bytes(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*) override; + +private: + PowerStateSwitchNode(FirmwareSysFSDirectory&); + + void reboot(); + void poweroff(); +}; + +} diff --git a/Kernel/Firmware/SysFSFirmware.cpp b/Kernel/Firmware/SysFSFirmware.cpp index cb50481560..0691255133 100644 --- a/Kernel/Firmware/SysFSFirmware.cpp +++ b/Kernel/Firmware/SysFSFirmware.cpp @@ -6,6 +6,7 @@ #include <Kernel/Firmware/ACPI/Parser.h> #include <Kernel/Firmware/BIOS.h> +#include <Kernel/Firmware/PowerStateSwitch.h> #include <Kernel/Firmware/SysFSFirmware.h> #include <Kernel/Sections.h> @@ -24,8 +25,10 @@ void FirmwareSysFSDirectory::create_components() VERIFY(!bios_directory_or_error.is_error()); auto acpi_directory_or_error = ACPI::ACPISysFSDirectory::try_create(*this); VERIFY(!acpi_directory_or_error.is_error()); + auto power_state_switch_node = PowerStateSwitchNode::must_create(*this); m_components.append(bios_directory_or_error.release_value()); m_components.append(acpi_directory_or_error.release_value()); + m_components.append(power_state_switch_node); } UNMAP_AFTER_INIT FirmwareSysFSDirectory::FirmwareSysFSDirectory() diff --git a/Kernel/Process.h b/Kernel/Process.h index 9c0ab672da..95376f3b12 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -388,8 +388,6 @@ public: KResultOr<FlatPtr> sys$kill_thread(pid_t tid, int signal); KResultOr<FlatPtr> sys$rename(Userspace<const Syscall::SC_rename_params*>); KResultOr<FlatPtr> sys$mknod(Userspace<const Syscall::SC_mknod_params*>); - KResultOr<FlatPtr> sys$halt(); - KResultOr<FlatPtr> sys$reboot(); KResultOr<FlatPtr> sys$realpath(Userspace<const Syscall::SC_realpath_params*>); KResultOr<FlatPtr> sys$getrandom(Userspace<void*>, size_t, unsigned int); KResultOr<FlatPtr> sys$getkeymap(Userspace<const Syscall::SC_getkeymap_params*>); diff --git a/Kernel/Syscalls/shutdown.cpp b/Kernel/Syscalls/shutdown.cpp deleted file mode 100644 index ee1e8b5a74..0000000000 --- a/Kernel/Syscalls/shutdown.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <Kernel/FileSystem/FileSystem.h> -#include <Kernel/Firmware/ACPI/Parser.h> -#include <Kernel/IO.h> -#include <Kernel/Process.h> -#include <Kernel/TTY/ConsoleManagement.h> - -namespace Kernel { - -KResultOr<FlatPtr> Process::sys$reboot() -{ - VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) - if (!is_superuser()) - return EPERM; - - REQUIRE_NO_PROMISES; - - dbgln("acquiring FS locks..."); - FileSystem::lock_all(); - dbgln("syncing mounted filesystems..."); - FileSystem::sync(); - dbgln("attempting reboot via ACPI"); - if (ACPI::is_enabled()) - ACPI::Parser::the()->try_acpi_reboot(); - dbgln("attempting reboot via KB Controller..."); - IO::out8(0x64, 0xFE); - - return 0; -} - -KResultOr<FlatPtr> Process::sys$halt() -{ - VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) - if (!is_superuser()) - return EPERM; - - REQUIRE_NO_PROMISES; - ConsoleManagement::the().switch_to_debug(); - - dbgln("acquiring FS locks..."); - FileSystem::lock_all(); - dbgln("syncing mounted filesystems..."); - FileSystem::sync(); - dbgln("attempting system shutdown..."); - // QEMU Shutdown - IO::out16(0x604, 0x2000); - // If we're here, the shutdown failed. Try VirtualBox shutdown. - IO::out16(0x4004, 0x3400); - // VirtualBox shutdown failed. Try Bochs/Old QEMU shutdown. - IO::out16(0xb004, 0x2000); - dbgln("shutdown attempts failed, applications will stop responding."); - dmesgln("Shutdown can't be completed. It's safe to turn off the computer!"); - Processor::halt(); -} - -} |