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 + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +mode_t PowerStateSwitchNode::permissions() const +{ + return S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; +} + +UNMAP_AFTER_INIT NonnullRefPtr 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 PowerStateSwitchNode::write_bytes(off_t offset, size_t count, UserOrKernelBuffer const& data, OpenFileDescription*) +{ + if (Checked::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 + * Copyright (c) 2021, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class PowerStateSwitchNode final : public SysFSComponent { +public: + static NonnullRefPtr must_create(FirmwareSysFSDirectory&); + virtual mode_t permissions() const override; + virtual KResultOr 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 #include +#include #include #include @@ -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 sys$kill_thread(pid_t tid, int signal); KResultOr sys$rename(Userspace); KResultOr sys$mknod(Userspace); - KResultOr sys$halt(); - KResultOr sys$reboot(); KResultOr sys$realpath(Userspace); KResultOr sys$getrandom(Userspace, size_t, unsigned int); KResultOr sys$getkeymap(Userspace); 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 - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace Kernel { - -KResultOr 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 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(); -} - -} diff --git a/Userland/Libraries/LibC/unistd.cpp b/Userland/Libraries/LibC/unistd.cpp index 7f7aa566c4..a902910424 100644 --- a/Userland/Libraries/LibC/unistd.cpp +++ b/Userland/Libraries/LibC/unistd.cpp @@ -715,18 +715,6 @@ int fsync(int fd) __RETURN_WITH_ERRNO(rc, rc, -1); } -int halt() -{ - int rc = syscall(SC_halt); - __RETURN_WITH_ERRNO(rc, rc, -1); -} - -int reboot() -{ - int rc = syscall(SC_reboot); - __RETURN_WITH_ERRNO(rc, rc, -1); -} - int mount(int source_fd, const char* target, const char* fs_type, int flags) { if (!target || !fs_type) { diff --git a/Userland/Libraries/LibC/unistd.h b/Userland/Libraries/LibC/unistd.h index 2cdfb4df5c..d738aaa32d 100644 --- a/Userland/Libraries/LibC/unistd.h +++ b/Userland/Libraries/LibC/unistd.h @@ -108,8 +108,6 @@ int chown(const char* pathname, uid_t, gid_t); int fchown(int fd, uid_t, gid_t); int ftruncate(int fd, off_t length); int truncate(const char* path, off_t length); -int halt(); -int reboot(); int mount(int source_fd, const char* target, const char* fs_type, int flags); int umount(const char* mountpoint); int pledge(const char* promises, const char* execpromises); diff --git a/Userland/Utilities/reboot.cpp b/Userland/Utilities/reboot.cpp index 82b716540c..f564c199a5 100644 --- a/Userland/Utilities/reboot.cpp +++ b/Userland/Utilities/reboot.cpp @@ -1,16 +1,24 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include int main(int, char**) { - if (reboot() < 0) { - perror("reboot"); + int power_state_switch_node = open("/sys/firmware/power_state", O_WRONLY); + if (power_state_switch_node < 0) { + perror("open"); + return 1; + } + const char* value = "1"; + if (write(power_state_switch_node, value, 1) < 0) { + perror("write"); return 1; } return 0; diff --git a/Userland/Utilities/shutdown.cpp b/Userland/Utilities/shutdown.cpp index a6ab3ca7d3..80f724f4ce 100644 --- a/Userland/Utilities/shutdown.cpp +++ b/Userland/Utilities/shutdown.cpp @@ -1,28 +1,25 @@ /* * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2021, Liav A. * * SPDX-License-Identifier: BSD-2-Clause */ -#include +#include #include #include -int main(int argc, char** argv) +int main(int, char**) { - bool now = false; - - Core::ArgsParser args_parser; - args_parser.add_option(now, "Shut down now", "now", 'n'); - args_parser.parse(argc, argv); - - if (now) { - if (halt() < 0) { - perror("shutdown"); - return 1; - } - } else { - args_parser.print_usage(stderr, argv[0]); + int power_state_switch_node = open("/sys/firmware/power_state", O_WRONLY); + if (power_state_switch_node < 0) { + perror("open"); return 1; } + const char* value = "2"; + if (write(power_state_switch_node, value, 1) < 0) { + perror("write"); + return 1; + } + return 0; }